#i105937# Much improved gradient support for canvas/basegfx/drawinglayer.

See http://blog.thebehrens.net/2009/07/28/hackweek-iv-canvas-convwatch/ for more background information
This commit is contained in:
thb
2009-10-16 00:43:16 +02:00
parent 9b9d44ee50
commit 1837a267a2
24 changed files with 1024 additions and 679 deletions

View File

@@ -36,6 +36,8 @@
#include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/vector/b2dvector.hxx> #include <basegfx/vector/b2dvector.hxx>
namespace rtl { class OUString; }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace basegfx namespace basegfx
@@ -79,6 +81,10 @@ namespace basegfx
double getRotate() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfRotate; } double getRotate() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfRotate; }
double getShearX() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfShearX; } double getShearX() const { const_cast< DecomposedB2DHomMatrixContainer* >(this)->impCheckDecompose(); return mfShearX; }
}; };
/// Returns a string with svg's "matrix(m00,m10,m01,m11,m02,m12)" representation
::rtl::OUString exportToSvg( const B2DHomMatrix& rMatrix );
} // end of namespace basegfx } // end of namespace basegfx
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@@ -112,7 +112,7 @@ namespace basegfx
/** clamp given value against given minimum and maximum values /** 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) if(value < minimum)
{ {

View File

@@ -37,6 +37,9 @@
#include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/numeric/ftools.hxx> #include <basegfx/numeric/ftools.hxx>
#include <vector>
#include <algorithm>
namespace basegfx namespace basegfx
{ {
/** Gradient definition as used in ODF 1.2 /** Gradient definition as used in ODF 1.2
@@ -78,6 +81,8 @@ namespace basegfx
{ {
/** Create matrix for ODF's linear gradient definition /** Create matrix for ODF's linear gradient definition
Note that odf linear gradients are varying in y direction.
@param o_rGradientInfo @param o_rGradientInfo
Receives the calculated texture transformation matrix (for Receives the calculated texture transformation matrix (for
use with standard [0,1]x[0,1] texture coordinates) use with standard [0,1]x[0,1] texture coordinates)
@@ -109,7 +114,7 @@ namespace basegfx
@param rUV @param rUV
Current uv coordinate. Values outside [0,1] will be Current uv coordinate. Values outside [0,1] will be
clamped. clamped. Assumes gradient color varies along the y axis.
@param rGradInfo @param rGradInfo
Gradient info, for transformation and number of steps Gradient info, for transformation and number of steps
@@ -129,6 +134,14 @@ namespace basegfx
/** Create matrix for ODF's axial gradient definition /** Create matrix for ODF's axial gradient definition
Note that odf axial gradients are varying in y
direction. Note further that you can map the axial
gradient to a linear gradient (in case you want or need to
avoid an extra gradient renderer), by using
createLinearODFGradientInfo() instead, shifting the
resulting texture transformation by 0.5 to the top and
appending the same stop colors again, but mirrored.
@param o_rGradientInfo @param o_rGradientInfo
Receives the calculated texture transformation matrix (for Receives the calculated texture transformation matrix (for
use with standard [0,1]x[0,1] texture coordinates) use with standard [0,1]x[0,1] texture coordinates)
@@ -160,7 +173,7 @@ namespace basegfx
@param rUV @param rUV
Current uv coordinate. Values outside [0,1] will be Current uv coordinate. Values outside [0,1] will be
clamped. clamped. Assumes gradient color varies along the y axis.
@param rGradInfo @param rGradInfo
Gradient info, for transformation and number of steps Gradient info, for transformation and number of steps
@@ -394,7 +407,6 @@ namespace basegfx
{ {
return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs
} }
} }
} }

View File

@@ -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

View File

@@ -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 */

View File

@@ -89,6 +89,8 @@ mkdir: %_DEST%\inc%_EXT%\basegfx\tuple
mkdir: %_DEST%\inc%_EXT%\basegfx\tools mkdir: %_DEST%\inc%_EXT%\basegfx\tools
..\inc\basegfx\tools\canvastools.hxx %_DEST%\inc%_EXT%\basegfx\tools\canvastools.hxx ..\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\unopolypolygon.hxx %_DEST%\inc%_EXT%\basegfx\tools\unopolypolygon.hxx
..\inc\basegfx\tools\rectcliptools.hxx %_DEST%\inc%_EXT%\basegfx\tools\rectcliptools.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 ..\inc\basegfx\tools\tools.hxx %_DEST%\inc%_EXT%\basegfx\tools\tools.hxx

View File

@@ -33,11 +33,39 @@
#include "precompiled_basegfx.hxx" #include "precompiled_basegfx.hxx"
#include <basegfx/matrix/b2dhommatrixtools.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace basegfx namespace basegfx
{ {
::rtl::OUString exportToSvg( const B2DHomMatrix& rMatrix )
{
rtl::OUStringBuffer aStrBuf;
aStrBuf.appendAscii("matrix(");
aStrBuf.append(rMatrix.get(0,0));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,0));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(0,1));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,1));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(0,2));
aStrBuf.appendAscii(", ");
aStrBuf.append(rMatrix.get(1,2));
aStrBuf.appendAscii(")");
return aStrBuf.makeStringAndClear();
}
} // end of namespace basegfx } // end of namespace basegfx
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@@ -52,6 +52,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity(); o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps; o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth()); double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight()); double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX()); double fTargetOffsetX(rTargetRange.getMinX());
@@ -70,7 +72,23 @@ namespace basegfx
fTargetSizeY = fNewY; fTargetSizeY = fNewY;
} }
// add object scale before rotate double fSizeWithoutBorder=0;
double fTranslateY=0;
if( bAxial )
{
fSizeWithoutBorder = (1.0 - fBorder) * 0.5;
fTranslateY = 0.5;
}
else
{
fSizeWithoutBorder = 1.0 - fBorder;
fTranslateY = fBorder;
}
if(!fTools::equal(fSizeWithoutBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(1.0, fSizeWithoutBorder);
o_rGradientInfo.maTextureTransform.translate(0.0, fTranslateY);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
// add texture rotate after scale to keep perpendicular angles // add texture rotate after scale to keep perpendicular angles
@@ -90,24 +108,9 @@ namespace basegfx
// prepare aspect for texture // prepare aspect for texture
o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform // build transform from u,v to [0.0 .. 1.0].
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert(); o_rGradientInfo.maBackTextureTransform.invert();
double fSizeWithoutBorder=0;
if( bAxial )
{
fSizeWithoutBorder = (1.0 - fBorder) * 0.5;
o_rGradientInfo.maBackTextureTransform.translate(0.0, -0.5);
}
else
{
fSizeWithoutBorder = 1.0 - fBorder;
o_rGradientInfo.maBackTextureTransform.translate(0.0, -fBorder);
}
if(!fTools::equal(fSizeWithoutBorder, 0.0))
o_rGradientInfo.maBackTextureTransform.scale(1.0, 1.0 / fSizeWithoutBorder);
} }
/** Most of the setup for radial & ellipsoidal gradient is the same, /** Most of the setup for radial & ellipsoidal gradient is the same,
@@ -125,6 +128,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity(); o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps; o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth()); double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight()); double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX()); double fTargetOffsetX(rTargetRange.getMinX());
@@ -147,7 +152,11 @@ namespace basegfx
fTargetSizeY = 1.4142 * fTargetSizeY; fTargetSizeY = 1.4142 * fTargetSizeY;
} }
// add object scale before rotate const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder);
o_rGradientInfo.maTextureTransform.translate(0.5, 0.5);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
if( !bCircular ) if( !bCircular )
@@ -155,9 +164,8 @@ namespace basegfx
// add texture rotate after scale to keep perpendicular angles // add texture rotate after scale to keep perpendicular angles
if(0.0 != fAngle) if(0.0 != fAngle)
{ {
B2DPoint aCenter(0.5, 0.5); const B2DPoint aCenter(0.5*fTargetSizeX,
aCenter *= o_rGradientInfo.maTextureTransform; 0.5*fTargetSizeY);
o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
o_rGradientInfo.maTextureTransform.rotate(fAngle); o_rGradientInfo.maTextureTransform.rotate(fAngle);
o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY()); o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
@@ -178,17 +186,9 @@ namespace basegfx
// prepare aspect for texture // prepare aspect for texture
o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0; o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform // build transform from u,v to [0.0 .. 1.0].
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert(); o_rGradientInfo.maBackTextureTransform.invert();
o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
{
const double fFactor(1.0 / fHalfBorder);
o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
}
} }
/** Setup for rect & square gradient is exactly the same. Factored out /** Setup for rect & square gradient is exactly the same. Factored out
@@ -205,6 +205,8 @@ namespace basegfx
o_rGradientInfo.maBackTextureTransform.identity(); o_rGradientInfo.maBackTextureTransform.identity();
o_rGradientInfo.mnSteps = nSteps; o_rGradientInfo.mnSteps = nSteps;
fAngle = -fAngle;
double fTargetSizeX(rTargetRange.getWidth()); double fTargetSizeX(rTargetRange.getWidth());
double fTargetSizeY(rTargetRange.getHeight()); double fTargetSizeY(rTargetRange.getHeight());
double fTargetOffsetX(rTargetRange.getMinX()); double fTargetOffsetX(rTargetRange.getMinX());
@@ -223,15 +225,18 @@ namespace basegfx
fTargetSizeY = fNewY; fTargetSizeY = fNewY;
} }
// add object scale before rotate const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
o_rGradientInfo.maTextureTransform.scale(fHalfBorder, fHalfBorder);
o_rGradientInfo.maTextureTransform.translate(0.5, 0.5);
o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY); o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
// add texture rotate after scale to keep perpendicular angles // add texture rotate after scale to keep perpendicular angles
if(0.0 != fAngle) if(0.0 != fAngle)
{ {
B2DPoint aCenter(0.5, 0.5); const B2DPoint aCenter(0.5*fTargetSizeX,
aCenter *= o_rGradientInfo.maTextureTransform; 0.5*fTargetSizeY);
o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY()); o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
o_rGradientInfo.maTextureTransform.rotate(fAngle); o_rGradientInfo.maTextureTransform.rotate(fAngle);
o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY()); o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
@@ -254,14 +259,6 @@ namespace basegfx
// build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform; o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
o_rGradientInfo.maBackTextureTransform.invert(); o_rGradientInfo.maBackTextureTransform.invert();
o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
const double fHalfBorder((1.0 - fBorder) * 0.5);
if(!fTools::equal(fHalfBorder, 0.0))
{
const double fFactor(1.0 / fHalfBorder);
o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
}
} }
namespace tools namespace tools

View File

@@ -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));
}
}
}

View File

@@ -44,6 +44,7 @@ ENABLE_EXCEPTIONS=TRUE
SLOFILES= $(SLO)$/canvastools.obj \ SLOFILES= $(SLO)$/canvastools.obj \
$(SLO)$/gradienttools.obj \ $(SLO)$/gradienttools.obj \
$(SLO)$/debugplotter.obj \ $(SLO)$/debugplotter.obj \
$(SLO)$/keystoplerp.obj \
$(SLO)$/liangbarsky.obj \ $(SLO)$/liangbarsky.obj \
$(SLO)$/tools.obj \ $(SLO)$/tools.obj \
$(SLO)$/unopolypolygon.obj $(SLO)$/unopolypolygon.obj

View File

@@ -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;

View File

@@ -46,6 +46,7 @@ SHL1OBJS= \
$(SLO)$/basegfx1d.obj \ $(SLO)$/basegfx1d.obj \
$(SLO)$/basegfx2d.obj \ $(SLO)$/basegfx2d.obj \
$(SLO)$/basegfx3d.obj \ $(SLO)$/basegfx3d.obj \
$(SLO)$/basegfxtools.obj \
$(SLO)$/testtools.obj $(SLO)$/testtools.obj
# linking statically against basegfx parts # linking statically against basegfx parts

View File

@@ -33,11 +33,11 @@
#include <rtl/ref.hxx> #include <rtl/ref.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp> #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/beans/XPropertySet.hpp>
#include <com/sun/star/util/XUpdatable.hpp> #include <com/sun/star/util/XUpdatable.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XColorSpace.hpp> #include <com/sun/star/rendering/XColorSpace.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <canvas/parametricpolypolygon.hxx> #include <canvas/parametricpolypolygon.hxx>
#include <canvas/propertysethelper.hxx> #include <canvas/propertysethelper.hxx>
@@ -50,8 +50,7 @@ namespace canvas
/** Helper template base class for XGraphicDevice implementations. /** Helper template base class for XGraphicDevice implementations.
This base class provides partial implementations of the This base class provides partial implementations of the
XGraphicDevice-related interface, such as XGraphicDevice-related interface, such as XColorSpace.
XParametricPolyPolygon2DFactory and XColorSpace.
This template basically interposes itself between the full This template basically interposes itself between the full
interface you implement (i.e. not restricted to XGraphicDevice interface you implement (i.e. not restricted to XGraphicDevice
@@ -249,7 +248,7 @@ namespace canvas
return maDeviceHelper.createVolatileAlphaBitmap( this, size ); 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; return this;
} }
@@ -268,79 +267,26 @@ namespace canvas
return maDeviceHelper.enterFullScreenMode( bEnter ); return maDeviceHelper.enterFullScreenMode( bEnter );
} }
// XParametricPolyPolygon2DFactory // XMultiServiceFactory
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, 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)
::com::sun::star::uno::RuntimeException)
{ {
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >( return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createLinearHorizontalGradient( this, ParametricPolyPolygon::create(this,
colors, aServiceSpecifier,
stops ) ); ::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, 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)
::com::sun::star::uno::RuntimeException)
{ {
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >( return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >(
ParametricPolyPolygon::createAxialHorizontalGradient( this, ParametricPolyPolygon::create(this,
colors, aServiceSpecifier,
stops ) ); 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, virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames( ) throw (::com::sun::star::uno::RuntimeException)
::com::sun::star::uno::RuntimeException)
{ {
return ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XParametricPolyPolygon2D >( return ParametricPolyPolygon::getAvailableServiceNames();
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 >();
} }

View File

@@ -417,28 +417,6 @@ namespace canvas
*/ */
::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange ); ::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. /** Retrieve various internal properties of the actual canvas implementation.
This method retrieves a bunch of internal, implementation- This method retrieves a bunch of internal, implementation-

View File

@@ -33,7 +33,7 @@
#include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/rendering/XGraphicDevice.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 <cppuhelper/compbase2.hxx>
#include <comphelper/broadcasthelper.hxx> #include <comphelper/broadcasthelper.hxx>
#include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b2dpolygon.hxx>
@@ -62,7 +62,6 @@ namespace canvas
enum GradientType enum GradientType
{ {
GRADIENT_LINEAR, GRADIENT_LINEAR,
GRADIENT_AXIAL,
GRADIENT_ELLIPTICAL, GRADIENT_ELLIPTICAL,
GRADIENT_RECTANGULAR GRADIENT_RECTANGULAR
}; };
@@ -103,24 +102,11 @@ namespace canvas
const GradientType meType; const GradientType meType;
}; };
static ParametricPolyPolygon* createLinearHorizontalGradient( const ::com::sun::star::uno::Reference< static ::com::sun::star::uno::Sequence< ::rtl::OUString > getAvailableServiceNames();
::com::sun::star::rendering::XGraphicDevice >& rDevice, static ParametricPolyPolygon* create(
const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< double > >& colors, const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XGraphicDevice >& rDevice,
const ::com::sun::star::uno::Sequence< double >& stops ); const ::rtl::OUString& rServiceName,
static ParametricPolyPolygon* createAxialHorizontalGradient( const ::com::sun::star::uno::Reference< const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& rArgs );
::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 );
/// Dispose all internal references /// Dispose all internal references
virtual void SAL_CALL disposing(); virtual void SAL_CALL disposing();
@@ -143,6 +129,20 @@ namespace canvas
~ParametricPolyPolygon(); // we're a ref-counted UNO class. _We_ destroy ourselves. ~ParametricPolyPolygon(); // we're a ref-counted UNO class. _We_ destroy ourselves.
private: 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 /// Private, because objects can only be created from the static factories
ParametricPolyPolygon( const ::com::sun::star::uno::Reference< ParametricPolyPolygon( const ::com::sun::star::uno::Reference<

View File

@@ -44,7 +44,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp> #include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp> #include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase7.hxx> #include <cppuhelper/compbase7.hxx>
#include <comphelper/uno3.hxx> #include <comphelper/uno3.hxx>
@@ -68,7 +67,7 @@ namespace cairocanvas
typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas, typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas,
::com::sun::star::rendering::XIntegerBitmap, ::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice, ::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory, ::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::util::XUpdatable, ::com::sun::star::util::XUpdatable,
::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XPropertySet,
::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base; ::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base;

View File

@@ -56,6 +56,8 @@
#include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/tools/canvastools.hxx> #include <basegfx/tools/canvastools.hxx>
#include <basegfx/tools/keystoplerp.hxx>
#include <basegfx/tools/lerp.hxx>
#include <comphelper/sequence.hxx> #include <comphelper/sequence.hxx>
#include <cppuhelper/compbase1.hxx> #include <cppuhelper/compbase1.hxx>
@@ -73,6 +75,7 @@
#include "cairo_canvashelper.hxx" #include "cairo_canvashelper.hxx"
#include "cairo_canvasbitmap.hxx" #include "cairo_canvasbitmap.hxx"
#include <boost/tuple/tuple.hpp>
#include <algorithm> #include <algorithm>
using namespace ::cairo; using namespace ::cairo;
@@ -122,9 +125,29 @@ namespace cairocanvas
mpCairo = pSurface->getCairo(); mpCairo = pSurface->getCairo();
} }
static void setColor( Cairo* pCairo,
const uno::Sequence<double>& rColor )
{
if( rColor.getLength() > 3 )
{
const double alpha = rColor[3];
cairo_set_source_rgba( pCairo,
alpha*rColor[0],
alpha*rColor[1],
alpha*rColor[2],
alpha );
}
else if( rColor.getLength() == 3 )
cairo_set_source_rgb( pCairo,
rColor[0],
rColor[1],
rColor[2] );
}
void CanvasHelper::useStates( const rendering::ViewState& viewState, void CanvasHelper::useStates( const rendering::ViewState& viewState,
const rendering::RenderState& renderState, const rendering::RenderState& renderState,
bool setColor ) bool bSetColor )
{ {
Matrix aViewMatrix; Matrix aViewMatrix;
Matrix aRenderMatrix; Matrix aRenderMatrix;
@@ -158,19 +181,8 @@ namespace cairocanvas
OSL_TRACE ("render clip END"); OSL_TRACE ("render clip END");
} }
if( setColor ) { if( bSetColor )
if( renderState.DeviceColor.getLength() > 3 ) setColor(mpCairo.get(),renderState.DeviceColor);
cairo_set_source_rgba( mpCairo.get(),
renderState.DeviceColor [0],
renderState.DeviceColor [1],
renderState.DeviceColor [2],
renderState.DeviceColor [3] );
else if (renderState.DeviceColor.getLength() == 3)
cairo_set_source_rgb( mpCairo.get(),
renderState.DeviceColor [0],
renderState.DeviceColor [1],
renderState.DeviceColor [2] );
}
cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER ); cairo_operator_t compositingMode( CAIRO_OPERATOR_OVER );
switch( renderState.CompositeOperation ) switch( renderState.CompositeOperation )
@@ -665,11 +677,33 @@ namespace cairocanvas
double alpha = rColor[3]; double alpha = rColor[3];
// cairo expects premultiplied alpha // 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]*alpha, rColor[1]*alpha, rColor[2]*alpha, alpha );
//cairo_pattern_add_color_stop_rgba( pPattern, stop, rColor[0], rColor[1], rColor[2], alpha );
} }
} }
} }
static uno::Sequence<double> lerp(const uno::Sequence<double>& rLeft, const uno::Sequence<double>& rRight, double fAlpha)
{
if( rLeft.getLength() == 3 )
{
uno::Sequence<double> aRes(3);
aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
return aRes;
}
else if( rLeft.getLength() == 4 )
{
uno::Sequence<double> aRes(4);
aRes[0] = basegfx::tools::lerp(rLeft[0],rRight[0],fAlpha);
aRes[1] = basegfx::tools::lerp(rLeft[1],rRight[1],fAlpha);
aRes[2] = basegfx::tools::lerp(rLeft[2],rRight[2],fAlpha);
aRes[3] = basegfx::tools::lerp(rLeft[3],rRight[3],fAlpha);
return aRes;
}
return uno::Sequence<double>();
}
static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon ) static Pattern* patternFromParametricPolyPolygon( ::canvas::ParametricPolyPolygon& rPolygon )
{ {
Pattern* pPattern = NULL; Pattern* pPattern = NULL;
@@ -678,7 +712,6 @@ namespace cairocanvas
// undef macros from vclenum.hxx which conflicts with GradientType enum values // undef macros from vclenum.hxx which conflicts with GradientType enum values
#undef GRADIENT_LINEAR #undef GRADIENT_LINEAR
#undef GRADIENT_AXIAL
#undef GRADIENT_ELLIPTICAL #undef GRADIENT_ELLIPTICAL
switch( aValues.meType ) { switch( aValues.meType ) {
@@ -691,26 +724,17 @@ namespace cairocanvas
addColorStops( pPattern, aValues.maColors, aValues.maStops ); addColorStops( pPattern, aValues.maColors, aValues.maStops );
break; break;
// FIXME: NYI
case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
x0 = 0;
y0 = 0;
x1 = 1;
y1 = 0;
pPattern = cairo_pattern_create_linear( x0, y0, x1, y1 );
addColorStops( pPattern, aValues.maColors, aValues.maStops );
break;
case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
cx = 0.5; cx = 0;
cy = 0.5; cy = 0;
r0 = 0; r0 = 0;
r1 = 0.5; r1 = 1;
pPattern = cairo_pattern_create_radial( cx, cy, r0, cx, cy, r1 ); pPattern = cairo_pattern_create_radial( cx, cy, r0, cy, cy, r1 );
addColorStops( pPattern, aValues.maColors, aValues.maStops, true ); addColorStops( pPattern, aValues.maColors, aValues.maStops, true );
break; break;
default:
break;
} }
return pPattern; return pPattern;
@@ -719,7 +743,8 @@ namespace cairocanvas
static void doOperation( Operation aOperation, static void doOperation( Operation aOperation,
Cairo* pCairo, Cairo* pCairo,
const uno::Sequence< rendering::Texture >* pTextures, const uno::Sequence< rendering::Texture >* pTextures,
const SurfaceProviderRef& pDevice ) const SurfaceProviderRef& pDevice,
const basegfx::B2DRange& rBounds )
{ {
switch( aOperation ) { switch( aOperation ) {
case Fill: case Fill:
@@ -790,19 +815,70 @@ namespace cairocanvas
cairo_matrix_init( &aTextureMatrix, cairo_matrix_init( &aTextureMatrix,
aTransform.m00, aTransform.m10, aTransform.m01, aTransform.m00, aTransform.m10, aTransform.m01,
aTransform.m11, aTransform.m02, aTransform.m12); aTransform.m11, aTransform.m02, aTransform.m12);
Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl ); if( pPolyImpl->getValues().meType == canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR )
{
if( pPattern ) { // no general path gradient yet in cairo; emulate then
OSL_TRACE( "filling with pattern" );
cairo_save( pCairo ); cairo_save( pCairo );
cairo_clip( pCairo );
// fill bound rect with start color
cairo_rectangle( pCairo, rBounds.getMinX(), rBounds.getMinY(),
rBounds.getWidth(), rBounds.getHeight() );
setColor(pCairo,pPolyImpl->getValues().maColors[0]);
cairo_fill(pCairo);
cairo_transform( pCairo, &aTextureMatrix );
// longest line in gradient bound rect
const unsigned int nGradientSize(
static_cast<unsigned int>(
::basegfx::B2DVector(rBounds.getMinimum() - rBounds.getMaximum()).getLength() + 1.0 ) );
// typical number for pixel of the same color (strip size)
const unsigned int nStripSize( nGradientSize < 50 ? 2 : 4 );
// use at least three steps, and at utmost the number of color
// steps
const unsigned int nStepCount(
::std::max(
3U,
::std::min(
nGradientSize / nStripSize,
128U )) + 1 );
const uno::Sequence<double>* pColors=&pPolyImpl->getValues().maColors[0];
basegfx::tools::KeyStopLerp aLerper(pPolyImpl->getValues().maStops);
for( unsigned int i=1; i<nStepCount; ++i )
{
const double fT( i/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
setColor(pCairo, lerp(pColors[nIndex], pColors[nIndex+1], fAlpha));
cairo_rectangle( pCairo, -1+fT, -1+fT, 2-2*fT, 2-2*fT );
cairo_fill(pCairo);
}
cairo_transform( pCairo, &aTextureMatrix );
cairo_set_source( pCairo, pPattern );
cairo_fill( pCairo );
cairo_restore( pCairo ); cairo_restore( pCairo );
}
else
{
Pattern* pPattern = patternFromParametricPolyPolygon( *pPolyImpl );
cairo_pattern_destroy( pPattern ); if( pPattern ) {
OSL_TRACE( "filling with pattern" );
cairo_save( pCairo );
cairo_transform( pCairo, &aTextureMatrix );
cairo_set_source( pCairo, pPattern );
cairo_fill( pCairo );
cairo_restore( pCairo );
cairo_pattern_destroy( pPattern );
}
} }
} }
} }
@@ -935,7 +1011,7 @@ namespace cairocanvas
if( aOperation == Fill && pTextures ) { if( aOperation == Fill && pTextures ) {
cairo_set_matrix( pCairo, &aOrigMatrix ); cairo_set_matrix( pCairo, &aOrigMatrix );
doOperation( aOperation, pCairo, pTextures, pDevice ); doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
cairo_set_matrix( pCairo, &aIdentityMatrix ); cairo_set_matrix( pCairo, &aIdentityMatrix );
} }
} else { } else {
@@ -948,7 +1024,7 @@ namespace cairocanvas
} }
} }
if( bOpToDo && ( aOperation != Fill || !pTextures ) ) if( bOpToDo && ( aOperation != Fill || !pTextures ) )
doOperation( aOperation, pCairo, pTextures, pDevice ); doOperation( aOperation, pCairo, pTextures, pDevice, aPolyPolygon.getB2DRange() );
cairo_set_matrix( pCairo, &aOrigMatrix ); cairo_set_matrix( pCairo, &aOrigMatrix );
@@ -1171,12 +1247,12 @@ namespace cairocanvas
const rendering::ViewState& viewState, const rendering::ViewState& viewState,
const rendering::RenderState& renderState, const rendering::RenderState& renderState,
const geometry::IntegerSize2D& rSize, const geometry::IntegerSize2D& rSize,
bool /*bModulateColors*/, bool bModulateColors,
bool bHasAlpha ) bool bHasAlpha )
{ {
SurfaceSharedPtr pSurface=pInputSurface; SurfaceSharedPtr pSurface=pInputSurface;
uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL); uno::Reference< rendering::XCachedPrimitive > rv = uno::Reference< rendering::XCachedPrimitive >(NULL);
geometry::IntegerSize2D aBitmapSize = rSize; geometry::IntegerSize2D aBitmapSize = rSize;
if( mpCairo ) { if( mpCairo ) {
cairo_save( mpCairo.get() ); cairo_save( mpCairo.get() );
@@ -1198,38 +1274,38 @@ namespace cairocanvas
::rtl::math::approxEqual( aMatrix.y0, 0 ) && ::rtl::math::approxEqual( aMatrix.y0, 0 ) &&
basegfx::fround( rSize.Width * aMatrix.xx ) > 8 && basegfx::fround( rSize.Width * aMatrix.xx ) > 8 &&
basegfx::fround( rSize.Height* aMatrix.yy ) > 8 ) basegfx::fround( rSize.Height* aMatrix.yy ) > 8 )
{ {
double dWidth, dHeight; double dWidth, dHeight;
dWidth = basegfx::fround( rSize.Width * aMatrix.xx ); dWidth = basegfx::fround( rSize.Width * aMatrix.xx );
dHeight = basegfx::fround( rSize.Height* aMatrix.yy ); dHeight = basegfx::fround( rSize.Height* aMatrix.yy );
aBitmapSize.Width = static_cast<sal_Int32>( dWidth ); aBitmapSize.Width = static_cast<sal_Int32>( dWidth );
aBitmapSize.Height = static_cast<sal_Int32>( dHeight ); aBitmapSize.Height = static_cast<sal_Int32>( dHeight );
SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface( SurfaceSharedPtr pScaledSurface = mpSurfaceProvider->createSurface(
::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ), ::basegfx::B2ISize( aBitmapSize.Width, aBitmapSize.Height ),
bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR ); bHasAlpha ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR );
CairoSharedPtr pCairo = pScaledSurface->getCairo(); CairoSharedPtr pCairo = pScaledSurface->getCairo();
cairo_set_operator( pCairo.get(), CAIRO_OPERATOR_SOURCE ); 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 // 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_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_set_source_surface( pCairo.get(), pSurface->getCairoSurface().get(), 0, 0 );
cairo_paint( pCairo.get() ); cairo_paint( pCairo.get() );
pSurface = pScaledSurface; pSurface = pScaledSurface;
aMatrix.xx = aMatrix.yy = 1; aMatrix.xx = aMatrix.yy = 1;
cairo_set_matrix( mpCairo.get(), &aMatrix ); cairo_set_matrix( mpCairo.get(), &aMatrix );
rv = uno::Reference< rendering::XCachedPrimitive >( rv = uno::Reference< rendering::XCachedPrimitive >(
new CachedBitmap( pSurface, viewState, renderState, new CachedBitmap( pSurface, viewState, renderState,
// cast away const, need to // cast away const, need to
// change refcount (as this is // change refcount (as this is
// ~invisible to client code, // ~invisible to client code,
// still logically const) // still logically const)
const_cast< rendering::XCanvas* >(pCanvas)) ); const_cast< rendering::XCanvas* >(pCanvas)) );
} }
if( !bHasAlpha && mbHaveAlpha ) if( !bHasAlpha && mbHaveAlpha )
{ {
@@ -1270,7 +1346,11 @@ namespace cairocanvas
cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE ); cairo_set_operator( mpCairo.get(), CAIRO_OPERATOR_SOURCE );
cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height ); cairo_rectangle( mpCairo.get(), 0, 0, aBitmapSize.Width, aBitmapSize.Height );
cairo_clip( mpCairo.get() ); 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() ); cairo_restore( mpCairo.get() );
} else } else
OSL_TRACE ("CanvasHelper called after it was disposed"); OSL_TRACE ("CanvasHelper called after it was disposed");
@@ -1309,15 +1389,35 @@ namespace cairocanvas
return rv; return rv;
} }
uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* , uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas,
const uno::Reference< rendering::XBitmap >& /*xBitmap*/, const uno::Reference< rendering::XBitmap >& xBitmap,
const rendering::ViewState& /*viewState*/, const rendering::ViewState& viewState,
const rendering::RenderState& /*renderState*/ ) 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. uno::Reference< rendering::XCachedPrimitive > rv;
return uno::Reference< rendering::XCachedPrimitive >(NULL); 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() uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice()

View File

@@ -42,7 +42,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp> #include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp> #include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase9.hxx> #include <cppuhelper/compbase9.hxx>
#include <comphelper/uno3.hxx> #include <comphelper/uno3.hxx>
@@ -66,7 +65,7 @@ namespace cairocanvas
typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas, typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap, ::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice, ::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory, ::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController, ::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener, ::com::sun::star::awt::XWindowListener,
::com::sun::star::util::XUpdatable, ::com::sun::star::util::XUpdatable,

View File

@@ -41,7 +41,7 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp> #include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.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 <cppuhelper/compbase8.hxx>
#include <comphelper/uno3.hxx> #include <comphelper/uno3.hxx>
@@ -60,7 +60,7 @@ namespace nullcanvas
typedef ::cppu::WeakComponentImplHelper8< ::com::sun::star::rendering::XSpriteCanvas, typedef ::cppu::WeakComponentImplHelper8< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap, ::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice, ::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory, ::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController, ::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener, ::com::sun::star::awt::XWindowListener,
::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XPropertySet,

View File

@@ -53,6 +53,87 @@ using namespace ::com::sun::star;
namespace canvas namespace canvas
{ {
uno::Sequence<rtl::OUString> ParametricPolyPolygon::getAvailableServiceNames()
{
uno::Sequence<rtl::OUString> aRet(3);
aRet[0] = rtl::OUString::createFromAscii("LinearGradient");
aRet[1] = rtl::OUString::createFromAscii("EllipticalGradient");
aRet[2] = rtl::OUString::createFromAscii("RectangularGradient");
return aRet;
}
ParametricPolyPolygon* ParametricPolyPolygon::create(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const ::rtl::OUString& rServiceName,
const uno::Sequence< uno::Any >& rArgs )
{
uno::Sequence< uno::Sequence< double > > colorSequence(2);
uno::Sequence< double > colorStops(2);
double fAspectRatio=1.0;
// defaults
uno::Sequence< rendering::RGBColor > rgbColors(1);
rgbColors[0] = rendering::RGBColor(0,0,0);
colorSequence[0] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
rgbColors[0] = rendering::RGBColor(1,1,1);
colorSequence[1] = rDevice->getDeviceColorSpace()->convertFromRGB(rgbColors);
colorStops[0] = 0;
colorStops[1] = 1;
// extract args
for( sal_Int32 i=0; i<rArgs.getLength(); ++i )
{
beans::PropertyValue aProp;
if( (rArgs[i] >>= aProp) )
{
if( aProp.Name.equalsAscii("Colors") )
{
aProp.Value >>= colorSequence;
}
else if( aProp.Name.equalsAscii("Stops") )
{
aProp.Value >>= colorStops;
}
else if( aProp.Name.equalsAscii("AspectRatio") )
{
aProp.Value >>= fAspectRatio;
}
}
}
if( rServiceName.equalsAscii("LinearGradient") )
{
return createLinearHorizontalGradient(rDevice, colorSequence, colorStops);
}
else if( rServiceName.equalsAscii("EllipticalGradient") )
{
return createEllipticalGradient(rDevice, colorSequence, colorStops, fAspectRatio);
}
else if( rServiceName.equalsAscii("RectangularGradient") )
{
return createRectangularGradient(rDevice, colorSequence, colorStops, fAspectRatio);
}
else if( rServiceName.equalsAscii("VerticalLineHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("OrthogonalLinesHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("ThreeCrossingLinesHatch") )
{
// TODO: NYI
}
else if( rServiceName.equalsAscii("FourCrossingLinesHatch") )
{
// TODO: NYI
}
return NULL;
}
ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient( ParametricPolyPolygon* ParametricPolyPolygon::createLinearHorizontalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice, const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors, const uno::Sequence< uno::Sequence< double > >& colors,
@@ -63,58 +144,35 @@ namespace canvas
return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops ); return new ParametricPolyPolygon( rDevice, GRADIENT_LINEAR, colors, stops );
} }
ParametricPolyPolygon* ParametricPolyPolygon::createAxialHorizontalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops )
{
// TODO(P2): hold gradient brush statically, and only setup
// the colors
return new ParametricPolyPolygon( rDevice, GRADIENT_AXIAL, colors, stops );
}
namespace
{
double calcAspectRatio( const geometry::RealRectangle2D& rBoundRect )
{
const double nWidth( rBoundRect.X2 - rBoundRect.X1 );
const double nHeight( rBoundRect.Y2 - rBoundRect.Y1 );
return ::basegfx::fTools::equalZero( nHeight ) ? 1.0 : fabs( nWidth / nHeight );
}
}
ParametricPolyPolygon* ParametricPolyPolygon::createEllipticalGradient( ParametricPolyPolygon* ParametricPolyPolygon::createEllipticalGradient(
const uno::Reference< rendering::XGraphicDevice >& rDevice, const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors, const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops, const uno::Sequence< double >& stops,
const geometry::RealRectangle2D& boundRect ) double fAspectRatio )
{ {
// TODO(P2): hold gradient polygon statically, and only setup // TODO(P2): hold gradient polygon statically, and only setup
// the colors // the colors
return new ParametricPolyPolygon( return new ParametricPolyPolygon(
rDevice, rDevice,
::basegfx::tools::createPolygonFromCircle( ::basegfx::tools::createPolygonFromCircle(
::basegfx::B2DPoint( 0.5, 0.5), 0.5 ), ::basegfx::B2DPoint(0,0), 1 ),
GRADIENT_ELLIPTICAL, GRADIENT_ELLIPTICAL,
colors, stops, colors, stops, fAspectRatio );
calcAspectRatio( boundRect ) );
} }
ParametricPolyPolygon* ParametricPolyPolygon::createRectangularGradient( const uno::Reference< rendering::XGraphicDevice >& rDevice, ParametricPolyPolygon* ParametricPolyPolygon::createRectangularGradient( const uno::Reference< rendering::XGraphicDevice >& rDevice,
const uno::Sequence< uno::Sequence< double > >& colors, const uno::Sequence< uno::Sequence< double > >& colors,
const uno::Sequence< double >& stops, const uno::Sequence< double >& stops,
const geometry::RealRectangle2D& boundRect ) double fAspectRatio )
{ {
// TODO(P2): hold gradient polygon statically, and only setup // TODO(P2): hold gradient polygon statically, and only setup
// the colors // the colors
return new ParametricPolyPolygon( return new ParametricPolyPolygon(
rDevice, rDevice,
::basegfx::tools::createPolygonFromRect( ::basegfx::tools::createPolygonFromRect(
::basegfx::B2DRectangle( 0.0, 0.0, 1.0, 1.0 ) ), ::basegfx::B2DRectangle( -1, -1, 1, 1 ) ),
GRADIENT_RECTANGULAR, GRADIENT_RECTANGULAR,
colors, stops, colors, stops, fAspectRatio );
calcAspectRatio( boundRect ) );
} }
void SAL_CALL ParametricPolyPolygon::disposing() void SAL_CALL ParametricPolyPolygon::disposing()

View File

@@ -41,7 +41,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp> #include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp> #include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase7.hxx> #include <cppuhelper/compbase7.hxx>
#include <comphelper/uno3.hxx> #include <comphelper/uno3.hxx>
@@ -63,7 +62,7 @@ namespace vclcanvas
typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas, typedef ::cppu::WeakComponentImplHelper7< ::com::sun::star::rendering::XBitmapCanvas,
::com::sun::star::rendering::XIntegerBitmap, ::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice, ::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory, ::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::util::XUpdatable, ::com::sun::star::util::XUpdatable,
::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XPropertySet,
::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base; ::com::sun::star::lang::XServiceName > GraphicDeviceBase_Base;

View File

@@ -57,6 +57,8 @@
#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dlinegeometry.hxx> #include <basegfx/polygon/b2dlinegeometry.hxx>
#include <basegfx/tools/tools.hxx> #include <basegfx/tools/tools.hxx>
#include <basegfx/tools/lerp.hxx>
#include <basegfx/tools/keystoplerp.hxx>
#include <basegfx/tools/canvastools.hxx> #include <basegfx/tools/canvastools.hxx>
#include <basegfx/numeric/ftools.hxx> #include <basegfx/numeric/ftools.hxx>
@@ -65,6 +67,9 @@
#include <canvas/canvastools.hxx> #include <canvas/canvastools.hxx>
#include <canvas/parametricpolypolygon.hxx> #include <canvas/parametricpolypolygon.hxx>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
#include "spritecanvas.hxx" #include "spritecanvas.hxx"
#include "canvashelper.hxx" #include "canvashelper.hxx"
#include "impltools.hxx" #include "impltools.hxx"
@@ -118,17 +123,13 @@ namespace vclcanvas
Since most of the code for linear and axial gradients are Since most of the code for linear and axial gradients are
the same, we've a unified method here the same, we've a unified method here
*/ */
void fillGeneralLinearGradient( OutputDevice& rOutDev, void fillLinearGradient( OutputDevice& rOutDev,
const ::basegfx::B2DHomMatrix& rTextureTransform, const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds, const ::Rectangle& rBounds,
int nStepCount, unsigned int nStepCount,
const ::Color& rColor1, const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor2, const std::vector< ::Color >& rColors )
bool bFillNonOverlapping,
bool bAxialGradient )
{ {
(void)bFillNonOverlapping;
// determine general position of gradient in relation to // determine general position of gradient in relation to
// the bound rect // the bound rect
// ===================================================== // =====================================================
@@ -207,36 +208,26 @@ namespace vclcanvas
// iteratively render all other strips // iteratively render all other strips
// ----------------------------------- // -----------------------------------
// ensure that nStepCount is odd, to have a well-defined // ensure that nStepCount matches color stop parity, to
// middle index for axial gradients. // have a well-defined middle color e.g. for axial
if( bAxialGradient && !(nStepCount % 2) ) // gradients.
if( (rColors.size() % 2) != (nStepCount % 2) )
++nStepCount; ++nStepCount;
const int nStepCountHalved( nStepCount / 2 ); basegfx::tools::KeyStopLerp aLerper(rValues.maStops);
// only iterate nStepCount-1 steps, as the last strip is // only iterate nStepCount-1 steps, as the last strip is
// explicitely painted below // explicitely painted below
for( int i=0; i<nStepCount-1; ++i ) for( unsigned int i=0; i<nStepCount-1; ++i )
{ {
// lerp color std::ptrdiff_t nIndex;
if( bAxialGradient ) double fAlpha;
{ boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount);
// axial gradient has a triangle-like interpolation function
const int iPrime( i<=nStepCountHalved ? i : nStepCount-i-1);
rOutDev.SetFillColor( rOutDev.SetFillColor(
Color( (UINT8)(((nStepCountHalved - iPrime)*rColor1.GetRed() + iPrime*rColor2.GetRed())/nStepCountHalved), Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(((nStepCountHalved - iPrime)*rColor1.GetGreen() + iPrime*rColor2.GetGreen())/nStepCountHalved), (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(((nStepCountHalved - iPrime)*rColor1.GetBlue() + iPrime*rColor2.GetBlue())/nStepCountHalved) ) ); (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
}
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) ) );
}
// copy right egde of polygon to left edge (and also // copy right egde of polygon to left edge (and also
// copy the closing point) // copy the closing point)
@@ -283,59 +274,18 @@ namespace vclcanvas
aTempPoly[3] = ::Point( ::basegfx::fround( rPoint4.getX() ), aTempPoly[3] = ::Point( ::basegfx::fround( rPoint4.getX() ),
::basegfx::fround( rPoint4.getY() ) ); ::basegfx::fround( rPoint4.getY() ) );
if( bAxialGradient ) rOutDev.SetFillColor( rColors.back() );
rOutDev.SetFillColor( rColor1 );
else
rOutDev.SetFillColor( rColor2 );
rOutDev.DrawPolygon( aTempPoly ); 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, void fillPolygonalGradient( OutputDevice& rOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1,
const ::Color& rColor2,
const ::basegfx::B2DHomMatrix& rTextureTransform, const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds, const ::Rectangle& rBounds,
int nStepCount, unsigned int nStepCount,
bool bFillNonOverlapping ) bool bFillNonOverlapping,
const ::canvas::ParametricPolyPolygon::Values& rValues,
const std::vector< ::Color >& rColors )
{ {
const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly ); const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly );
@@ -369,9 +319,6 @@ namespace vclcanvas
// apply scaling (possibly anisotrophic) to inner polygon // apply scaling (possibly anisotrophic) to inner polygon
// ------------------------------------------------------ // ------------------------------------------------------
// move center of scaling to origin
aInnerPolygonTransformMatrix.translate( -0.5, -0.5 );
// scale inner polygon according to aspect ratio: for // scale inner polygon according to aspect ratio: for
// wider-than-tall bounds (nAspectRatio > 1.0), the inner // wider-than-tall bounds (nAspectRatio > 1.0), the inner
// polygon, representing the gradient focus, must have // polygon, representing the gradient focus, must have
@@ -396,9 +343,6 @@ namespace vclcanvas
aInnerPolygonTransformMatrix.scale( 0.0, 0.0 ); aInnerPolygonTransformMatrix.scale( 0.0, 0.0 );
} }
// move origin back to former center of polygon
aInnerPolygonTransformMatrix.translate( 0.5, 0.5 );
// and finally, add texture transform to it. // and finally, add texture transform to it.
aInnerPolygonTransformMatrix *= rTextureTransform; aInnerPolygonTransformMatrix *= rTextureTransform;
@@ -406,8 +350,8 @@ namespace vclcanvas
aInnerPoly.transform( aInnerPolygonTransformMatrix ); aInnerPoly.transform( aInnerPolygonTransformMatrix );
const sal_Int32 nNumPoints( aOuterPoly.count() ); const sal_uInt32 nNumPoints( aOuterPoly.count() );
::Polygon aTempPoly( static_cast<USHORT>(nNumPoints+1) ); ::Polygon aTempPoly( static_cast<USHORT>(nNumPoints+1) );
// increase number of steps by one: polygonal gradients have // increase number of steps by one: polygonal gradients have
// the outermost polygon rendered in rColor2, and the // the outermost polygon rendered in rColor2, and the
@@ -425,37 +369,42 @@ namespace vclcanvas
// color). // color).
++nStepCount; ++nStepCount;
basegfx::tools::KeyStopLerp aLerper(rValues.maStops);
if( !bFillNonOverlapping ) if( !bFillNonOverlapping )
{ {
// fill background // fill background
rOutDev.SetFillColor( rColor1 ); rOutDev.SetFillColor( rColors.front() );
rOutDev.DrawRect( rBounds ); rOutDev.DrawRect( rBounds );
// render polygon // render polygon
// ============== // ==============
for( int i=1,p; i<nStepCount; ++i ) for( unsigned int i=1,p; i<nStepCount; ++i )
{ {
const double fT( i/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
// lerp color // lerp color
rOutDev.SetFillColor( rOutDev.SetFillColor(
Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount), Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount), (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) ); (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
// scale and render polygon, by interpolating between // scale and render polygon, by interpolating between
// outer and inner polygon. // outer and inner polygon.
// calc interpolation parameter in [0,1] range
const double nT( (nStepCount-i)/double(nStepCount) );
for( p=0; p<nNumPoints; ++p ) for( p=0; p<nNumPoints; ++p )
{ {
const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) ); const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) );
const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) ); const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) );
aTempPoly[(USHORT)p] = ::Point( aTempPoly[(USHORT)p] = ::Point(
basegfx::fround( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ), basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ),
basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*rOuterPoint.getY() ) ); basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) );
} }
// close polygon explicitely // close polygon explicitely
@@ -489,13 +438,19 @@ namespace vclcanvas
aTempPolyPoly.Insert( aTempPoly ); aTempPolyPoly.Insert( aTempPoly );
aTempPolyPoly.Insert( aTempPoly2 ); aTempPolyPoly.Insert( aTempPoly2 );
for( int i=0,p; i<nStepCount; ++i ) for( unsigned int i=0,p; i<nStepCount; ++i )
{ {
const double fT( (i+1)/double(nStepCount) );
std::ptrdiff_t nIndex;
double fAlpha;
boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(fT);
// lerp color // lerp color
rOutDev.SetFillColor( rOutDev.SetFillColor(
Color( (UINT8)(((nStepCount - i)*rColor1.GetRed() + i*rColor2.GetRed())/nStepCount), Color( (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha)),
(UINT8)(((nStepCount - i)*rColor1.GetGreen() + i*rColor2.GetGreen())/nStepCount), (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha)),
(UINT8)(((nStepCount - i)*rColor1.GetBlue() + i*rColor2.GetBlue())/nStepCount) ) ); (UINT8)(basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha)) ));
#if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
if( i && !(i % 10) ) if( i && !(i % 10) )
@@ -506,17 +461,14 @@ namespace vclcanvas
// calculate the inner polygon, which is actually the // calculate the inner polygon, which is actually the
// start of the _next_ color strip. Thus, i+1 // start of the _next_ color strip. Thus, i+1
// calc interpolation parameter in [0,1] range
const double nT( (nStepCount-i-1)/double(nStepCount) );
for( p=0; p<nNumPoints; ++p ) for( p=0; p<nNumPoints; ++p )
{ {
const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) ); const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) );
const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) ); const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.getB2DPoint(p) );
aTempPoly[(USHORT)p] = ::Point( aTempPoly[(USHORT)p] = ::Point(
basegfx::fround( (1.0-nT)*rInnerPoint.getX() + nT*rOuterPoint.getX() ), basegfx::fround( fT*rInnerPoint.getX() + (1-fT)*rOuterPoint.getX() ),
basegfx::fround( (1.0-nT)*rInnerPoint.getY() + nT*rOuterPoint.getY() ) ); basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) );
} }
// close polygon explicitely // close polygon explicitely
@@ -549,46 +501,33 @@ namespace vclcanvas
void doGradientFill( OutputDevice& rOutDev, void doGradientFill( OutputDevice& rOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues, const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1, const std::vector< ::Color >& rColors,
const ::Color& rColor2,
const ::basegfx::B2DHomMatrix& rTextureTransform, const ::basegfx::B2DHomMatrix& rTextureTransform,
const ::Rectangle& rBounds, const ::Rectangle& rBounds,
int nStepCount, unsigned int nStepCount,
bool bFillNonOverlapping ) bool bFillNonOverlapping )
{ {
switch( rValues.meType ) switch( rValues.meType )
{ {
case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
fillLinearGradient( rOutDev, fillLinearGradient( rOutDev,
rColor1,
rColor2,
rTextureTransform, rTextureTransform,
rBounds, rBounds,
nStepCount, nStepCount,
bFillNonOverlapping ); rValues,
break; rColors );
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
fillAxialGradient( rOutDev,
rColor1,
rColor2,
rTextureTransform,
rBounds,
nStepCount,
bFillNonOverlapping );
break; break;
case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL: case ::canvas::ParametricPolyPolygon::GRADIENT_ELLIPTICAL:
// FALLTHROUGH intended // FALLTHROUGH intended
case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR: case ::canvas::ParametricPolyPolygon::GRADIENT_RECTANGULAR:
fillPolygonalGradient( rOutDev, fillPolygonalGradient( rOutDev,
rValues,
rColor1,
rColor2,
rTextureTransform, rTextureTransform,
rBounds, rBounds,
nStepCount, nStepCount,
bFillNonOverlapping ); bFillNonOverlapping,
rValues,
rColors );
break; break;
default: default:
@@ -597,11 +536,19 @@ namespace vclcanvas
} }
} }
int numColorSteps( const ::Color& rColor1, const ::Color& rColor2 )
{
return ::std::max(
labs( rColor1.GetRed() - rColor2.GetRed() ),
::std::max(
labs( rColor1.GetGreen() - rColor2.GetGreen() ),
labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) );
}
bool gradientFill( OutputDevice& rOutDev, bool gradientFill( OutputDevice& rOutDev,
OutputDevice* p2ndOutDev, OutputDevice* p2ndOutDev,
const ::canvas::ParametricPolyPolygon::Values& rValues, const ::canvas::ParametricPolyPolygon::Values& rValues,
const ::Color& rColor1, const std::vector< ::Color >& rColors,
const ::Color& rColor2,
const PolyPolygon& rPoly, const PolyPolygon& rPoly,
const rendering::ViewState& viewState, const rendering::ViewState& viewState,
const rendering::RenderState& renderState, const rendering::RenderState& renderState,
@@ -646,12 +593,9 @@ namespace vclcanvas
// calc step size // calc step size
// -------------- // --------------
const int nColorSteps( int nColorSteps = 0;
::std::max( for( size_t i=0; i<rColors.size()-1; ++i )
labs( rColor1.GetRed() - rColor2.GetRed() ), nColorSteps += numColorSteps(rColors[i],rColors[i+1]);
::std::max(
labs( rColor1.GetGreen() - rColor2.GetGreen() ),
labs( rColor1.GetBlue() - rColor2.GetBlue() ) ) ) );
// longest line in gradient bound rect // longest line in gradient bound rect
const int nGradientSize( const int nGradientSize(
@@ -690,8 +634,7 @@ namespace vclcanvas
rOutDev.IntersectClipRegion( aPolygonDeviceRectOrig ); rOutDev.IntersectClipRegion( aPolygonDeviceRectOrig );
doGradientFill( rOutDev, doGradientFill( rOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -704,8 +647,7 @@ namespace vclcanvas
p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig ); p2ndOutDev->IntersectClipRegion( aPolygonDeviceRectOrig );
doGradientFill( *p2ndOutDev, doGradientFill( *p2ndOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -723,8 +665,7 @@ namespace vclcanvas
doGradientFill( rOutDev, doGradientFill( rOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -737,8 +678,7 @@ namespace vclcanvas
p2ndOutDev->SetClipRegion( aPolyClipRegion ); p2ndOutDev->SetClipRegion( aPolyClipRegion );
doGradientFill( *p2ndOutDev, doGradientFill( *p2ndOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -753,8 +693,7 @@ namespace vclcanvas
rOutDev.SetRasterOp( ROP_XOR ); rOutDev.SetRasterOp( ROP_XOR );
doGradientFill( rOutDev, doGradientFill( rOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -765,8 +704,7 @@ namespace vclcanvas
rOutDev.SetRasterOp( ROP_XOR ); rOutDev.SetRasterOp( ROP_XOR );
doGradientFill( rOutDev, doGradientFill( rOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -779,8 +717,7 @@ namespace vclcanvas
p2ndOutDev->SetRasterOp( ROP_XOR ); p2ndOutDev->SetRasterOp( ROP_XOR );
doGradientFill( *p2ndOutDev, doGradientFill( *p2ndOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -791,8 +728,7 @@ namespace vclcanvas
p2ndOutDev->SetRasterOp( ROP_XOR ); p2ndOutDev->SetRasterOp( ROP_XOR );
doGradientFill( *p2ndOutDev, doGradientFill( *p2ndOutDev,
rValues, rValues,
rColor1, rColors,
rColor2,
aTextureTransform, aTextureTransform,
aPolygonDeviceRectOrig, aPolygonDeviceRectOrig,
nStepCount, nStepCount,
@@ -855,33 +791,41 @@ namespace vclcanvas
::canvas::ParametricPolyPolygon* pGradient = ::canvas::ParametricPolyPolygon* pGradient =
dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() ); dynamic_cast< ::canvas::ParametricPolyPolygon* >( textures[0].Gradient.get() );
if( pGradient ) if( pGradient && pGradient->getValues().maColors.getLength() )
{ {
// copy state from Gradient polypoly locally // copy state from Gradient polypoly locally
// (given object might change!) // (given object might change!)
const ::canvas::ParametricPolyPolygon::Values& rValues( const ::canvas::ParametricPolyPolygon::Values& rValues(
pGradient->getValues() ); pGradient->getValues() );
// TODO: use all the colors and place them on given positions/stops if( rValues.maColors.getLength() < 2 )
const ::Color aColor1( {
::vcl::unotools::stdColorSpaceSequenceToColor( rendering::RenderState aTempState=renderState;
rValues.maColors [0] ) ); aTempState.DeviceColor = rValues.maColors[0];
const ::Color aColor2( fillPolyPolygon(pCanvas, xPolyPolygon, viewState, aTempState);
::vcl::unotools::stdColorSpaceSequenceToColor( }
rValues.maColors [rValues.maColors.getLength () - 1] ) ); 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(E1): Return value
// TODO(F1): FillRule // TODO(F1): FillRule
gradientFill( mpOutDev->getOutDev(), gradientFill( mpOutDev->getOutDev(),
mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL, mp2ndOutDev.get() ? &mp2ndOutDev->getOutDev() : (OutputDevice*)NULL,
rValues, rValues,
aColor1, aColors,
aColor2, aPolyPoly,
aPolyPoly, viewState,
viewState, renderState,
renderState, textures[0],
textures[0], nTransparency );
nTransparency ); }
} }
else else
{ {

View File

@@ -42,7 +42,6 @@
#include <com/sun/star/rendering/XIntegerBitmap.hpp> #include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/XBufferController.hpp> #include <com/sun/star/rendering/XBufferController.hpp>
#include <com/sun/star/rendering/XParametricPolyPolygon2DFactory.hpp>
#include <cppuhelper/compbase9.hxx> #include <cppuhelper/compbase9.hxx>
#include <comphelper/uno3.hxx> #include <comphelper/uno3.hxx>
@@ -65,7 +64,7 @@ namespace vclcanvas
typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas, typedef ::cppu::WeakComponentImplHelper9< ::com::sun::star::rendering::XSpriteCanvas,
::com::sun::star::rendering::XIntegerBitmap, ::com::sun::star::rendering::XIntegerBitmap,
::com::sun::star::rendering::XGraphicDevice, ::com::sun::star::rendering::XGraphicDevice,
::com::sun::star::rendering::XParametricPolyPolygon2DFactory, ::com::sun::star::lang::XMultiServiceFactory,
::com::sun::star::rendering::XBufferController, ::com::sun::star::rendering::XBufferController,
::com::sun::star::awt::XWindowListener, ::com::sun::star::awt::XWindowListener,
::com::sun::star::util::XUpdatable, ::com::sun::star::util::XUpdatable,

View File

@@ -49,7 +49,6 @@
#include <com/sun/star/rendering/XGraphicDevice.hpp> #include <com/sun/star/rendering/XGraphicDevice.hpp>
#include <com/sun/star/rendering/TexturingMode.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/uno/Sequence.hxx>
#include <com/sun/star/geometry/RealPoint2D.hpp> #include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/rendering/ViewState.hpp> #include <com/sun/star/rendering/ViewState.hpp>
@@ -61,6 +60,7 @@
#include <com/sun/star/rendering/PathJoinType.hpp> #include <com/sun/star/rendering/PathJoinType.hpp>
#include <basegfx/tools/canvastools.hxx> #include <basegfx/tools/canvastools.hxx>
#include <basegfx/tools/gradienttools.hxx>
#include <basegfx/numeric/ftools.hxx> #include <basegfx/numeric/ftools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx> #include <basegfx/polygon/b2dpolygontools.hxx>
@@ -590,13 +590,12 @@ namespace cppcanvas
// discernible difference should be visible. // discernible difference should be visible.
nSteps > 64 ) nSteps > 64 )
{ {
uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory( uno::Reference< lang::XMultiServiceFactory> xFactory(
rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() ); rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
if( xFactory.is() ) if( xFactory.is() )
{ {
::basegfx::B2DHomMatrix aTextureTransformation; rendering::Texture aTexture;
rendering::Texture aTexture;
aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
@@ -631,242 +630,118 @@ namespace cppcanvas
uno::Sequence< uno::Sequence < double > > aColors(2); uno::Sequence< uno::Sequence < double > > aColors(2);
uno::Sequence< double > aStops(2); uno::Sequence< double > aStops(2);
aStops[0] = 0.0; if( rGradient.GetStyle() == GRADIENT_AXIAL )
aStops[1] = 1.0; {
aStops.realloc(3);
aColors.realloc(3);
aColors[0] = aStartColor; aStops[0] = 0.0;
aColors[1] = aEndColor; aStops[1] = 0.5;
aStops[2] = 1.0;
aColors[0] = aEndColor;
aColors[1] = aStartColor;
aColors[2] = aEndColor;
}
else
{
aStops[0] = 0.0;
aStops[1] = 1.0;
// Setup texture transformation aColors[0] = aStartColor;
// ---------------------------- aColors[1] = aEndColor;
}
const ::basegfx::B2DRectangle aBounds( const ::basegfx::B2DRectangle aBounds(
::basegfx::tools::getRange(aDevicePoly) ); ::basegfx::tools::getRange(aDevicePoly) );
const ::basegfx::B2DVector aOffset(
rGradient.GetOfsX() / 100.0,
rGradient.GetOfsY() / 100.0);
double fRotation( rGradient.GetAngle() * M_PI / 1800.0 );
const double fBorder( rGradient.GetBorder() / 100.0 );
// setup rotation angle. VCL rotates basegfx::B2DHomMatrix aRot90;
// counter-clockwise, while canvas transformation aRot90.rotate(M_PI_2);
// rotates clockwise
double nRotation( -rGradient.GetAngle() * M_PI / 1800.0 );
basegfx::ODFGradientInfo aGradInfo;
rtl::OUString aGradientService;
switch( rGradient.GetStyle() ) switch( rGradient.GetStyle() )
{ {
case GRADIENT_LINEAR: case GRADIENT_LINEAR:
// FALLTHROUGH intended basegfx::tools::createLinearODFGradientInfo(aGradInfo,
aBounds,
nSteps,
fBorder,
fRotation);
// map odf to svg gradient orientation - x
// instead of y direction
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
aGradientService = rtl::OUString::createFromAscii("LinearGradient");
break;
case GRADIENT_AXIAL: case GRADIENT_AXIAL:
{ {
// standard orientation for VCL linear basegfx::tools::createLinearODFGradientInfo(aGradInfo,
// gradient is vertical, thus, rotate 90 aBounds,
// degrees nSteps,
nRotation += M_PI/2.0; fBorder,
fRotation);
// map odf to svg gradient orientation - x
// instead of y direction
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
const double nBorder( // map odf axial gradient to 3-stop linear
::basegfx::pruneScaleValue( // gradient - shift left by 0.5
(1.0 - rGradient.GetBorder() / 100.0) ) ); basegfx::B2DHomMatrix aShift;
aShift.translate(-0.5,0);
aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aShift;
// shrink texture, to account for border aGradientService = rtl::OUString::createFromAscii("LinearGradient");
// (only in x direction, linear gradient break;
// is constant in y direction, anyway)
aTextureTransformation.scale( nBorder,
1.0 );
// linear gradients don't respect offsets
// (they are implicitely assumed to be
// 50%). linear gradients don't have
// border on both sides, only on the
// startColor side, axial gradients have
// border on both sides. As both gradients
// are invariant in y direction: leave y
// offset alone.
double nOffsetX( rGradient.GetBorder() / 200.0 );
// determine type of gradient (and necessary
// transformation matrix, should it be emulated by a
// generic gradient)
switch( rGradient.GetStyle() )
{
case GRADIENT_LINEAR:
nOffsetX = rGradient.GetBorder() / 100.0;
aTexture.Gradient = xFactory->createLinearHorizontalGradient( aColors,
aStops );
break;
case GRADIENT_AXIAL:
// vcl considers center color as start color
::std::swap(aColors[0],aColors[1]);
aTexture.Gradient = xFactory->createAxialHorizontalGradient( aColors,
aStops );
break;
default: // other cases can't happen
break;
}
// apply border offset values
aTextureTransformation.translate( nOffsetX,
0.0 );
// rotate texture according to gradient rotation
aTextureTransformation.translate( -0.5, -0.5 );
aTextureTransformation.rotate( nRotation );
// to let the first strip of a rotated
// gradient start at the _edge_ of the
// bound rect (and not, due to rotation,
// slightly inside), slightly enlarge the
// gradient:
//
// y/2 sin(alpha) + x/2 cos(alpha)
//
// (values to change are not actual
// gradient scales, but original bound
// rect dimensions. Since we still want
// the border setting to apply after that,
// we multiply with that as above for
// nScaleX)
const double nScale(
::basegfx::pruneScaleValue(
fabs( aBounds.getHeight()*sin(nRotation) ) +
fabs( aBounds.getWidth()*cos(nRotation) )));
aTextureTransformation.scale( nScale, nScale );
// translate back origin to center of
// primitive
aTextureTransformation.translate( 0.5*aBounds.getWidth(),
0.5*aBounds.getHeight() );
} }
break;
case GRADIENT_RADIAL: case GRADIENT_RADIAL:
// FALLTHROUGH intended basegfx::tools::createRadialODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder);
aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
break;
case GRADIENT_ELLIPTICAL: case GRADIENT_ELLIPTICAL:
// FALLTHROUGH intended basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder,
fRotation);
aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
break;
case GRADIENT_SQUARE: case GRADIENT_SQUARE:
// FALLTHROUGH intended basegfx::tools::createSquareODFGradientInfo(aGradInfo,
aBounds,
aOffset,
nSteps,
fBorder,
fRotation);
aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
break;
case GRADIENT_RECT: case GRADIENT_RECT:
{ basegfx::tools::createRectangularODFGradientInfo(aGradInfo,
// determine scale factors for the gradient (must aBounds,
// be scaled up from [0,1]x[0,1] rect to object aOffset,
// bounds). Will potentially changed in switch nSteps,
// statement below. fBorder,
// Respect border value, while doing so, the VCL fRotation);
// gradient's border will effectively shrink the aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
// resulting gradient. break;
double nScaleX( aBounds.getWidth() * (1.0 - rGradient.GetBorder() / 100.0) );
double nScaleY( aBounds.getHeight()* (1.0 - rGradient.GetBorder() / 100.0) );
// determine offset values. Since the border is
// divided half-by-half to both sides of the
// gradient, divide translation offset by an
// additional 2. Also respect offset here, but
// since VCL gradients have their center at [0,0]
// for zero offset, but canvas gradients have
// their top, left edge aligned with the
// primitive, and offset of 50% effectively must
// yield zero shift. Both values will potentially
// be adapted in switch statement below.
double nOffsetX( aBounds.getWidth() *
(2.0 * rGradient.GetOfsX() - 100.0 + rGradient.GetBorder()) / 200.0 );
double nOffsetY( aBounds.getHeight() *
(2.0 * rGradient.GetOfsY() - 100.0 + rGradient.GetBorder()) / 200.0 );
// determine type of gradient (and necessary
// transformation matrix, should it be emulated by a
// generic gradient)
switch( rGradient.GetStyle() )
{
case GRADIENT_RADIAL:
{
// create isotrophic scaling
if( nScaleX > nScaleY )
{
nOffsetY -= (nScaleX - nScaleY) * 0.5;
nScaleY = nScaleX;
}
else
{
nOffsetX -= (nScaleY - nScaleX) * 0.5;
nScaleX = nScaleY;
}
// enlarge gradient to match bound rect diagonal
aTextureTransformation.translate( -0.5, -0.5 );
const double nScale( hypot(aBounds.getWidth(), aBounds.getHeight()) / nScaleX );
aTextureTransformation.scale( nScale, nScale );
aTextureTransformation.translate( 0.5, 0.5 );
aTexture.Gradient = xFactory->createEllipticalGradient( aColors,
aStops,
geometry::RealRectangle2D(0.0,0.0,
1.0,1.0) );
}
break;
case GRADIENT_ELLIPTICAL:
{
// enlarge gradient slightly
aTextureTransformation.translate( -0.5, -0.5 );
const double nSqrt2( sqrt(2.0) );
aTextureTransformation.scale( nSqrt2,nSqrt2 );
aTextureTransformation.translate( 0.5, 0.5 );
aTexture.Gradient = xFactory->createEllipticalGradient(
aColors,
aStops,
::basegfx::unotools::rectangle2DFromB2DRectangle(
aBounds ));
}
break;
case GRADIENT_SQUARE:
// create isotrophic scaling
if( nScaleX > nScaleY )
{
nOffsetY -= (nScaleX - nScaleY) * 0.5;
nScaleY = nScaleX;
}
else
{
nOffsetX -= (nScaleY - nScaleX) * 0.5;
nScaleX = nScaleY;
}
aTexture.Gradient = xFactory->createRectangularGradient( aColors,
aStops,
geometry::RealRectangle2D(0.0,0.0,
1.0,1.0) );
break;
case GRADIENT_RECT:
aTexture.Gradient = xFactory->createRectangularGradient(
aColors,
aStops,
::basegfx::unotools::rectangle2DFromB2DRectangle(
aBounds ) );
break;
default: // other cases can't happen
break;
}
nScaleX = ::basegfx::pruneScaleValue( nScaleX );
nScaleY = ::basegfx::pruneScaleValue( nScaleY );
aTextureTransformation.scale( nScaleX, nScaleY );
// rotate texture according to gradient rotation
aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY );
aTextureTransformation.rotate( nRotation );
aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
aTextureTransformation.translate( nOffsetX, nOffsetY );
}
break;
default: default:
ENSURE_OR_THROW( false, ENSURE_OR_THROW( false,
"ImplRenderer::createGradientAction(): Unexpected gradient type" ); "ImplRenderer::createGradientAction(): Unexpected gradient type" );
break; break;
} }
@@ -877,31 +752,49 @@ namespace cppcanvas
// gradient will always display at the origin, and // gradient will always display at the origin, and
// not within the polygon bound (which might be // not within the polygon bound (which might be
// miles away from the origin). // miles away from the origin).
aTextureTransformation.translate( aBounds.getMinX(), aGradInfo.maTextureTransform.translate( aBounds.getMinX(),
aBounds.getMinY() ); aBounds.getMinY() );
::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform, ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
aTextureTransformation ); aGradInfo.maTextureTransform );
ActionSharedPtr pPolyAction( uno::Sequence<uno::Any> args(3);
internal::PolyPolyActionFactory::createPolyPolyAction( beans::PropertyValue aProp;
aDevicePoly, aProp.Name = rtl::OUString::createFromAscii("Colors");
rParms.mrCanvas, aProp.Value <<= aColors;
getState( rParms.mrStates ), args[0] <<= aProp;
aTexture ) ); aProp.Name = rtl::OUString::createFromAscii("Stops");
aProp.Value <<= aStops;
args[1] <<= aProp;
aProp.Name = rtl::OUString::createFromAscii("AspectRatio");
aProp.Value <<= aGradInfo.mfAspectRatio;
args[2] <<= aProp;
if( pPolyAction ) aTexture.Gradient.set(
xFactory->createInstanceWithArguments(aGradientService,
args),
uno::UNO_QUERY);
if( aTexture.Gradient.is() )
{ {
maActions.push_back( ActionSharedPtr pPolyAction(
MtfAction( internal::PolyPolyActionFactory::createPolyPolyAction(
pPolyAction, aDevicePoly,
rParms.mrCurrActionIndex ) ); rParms.mrCanvas,
getState( rParms.mrStates ),
aTexture ) );
rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1; if( pPolyAction )
{
maActions.push_back(
MtfAction(
pPolyAction,
rParms.mrCurrActionIndex ) );
rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
}
// done, using native gradients
return;
} }
// done, using native gradients
return;
} }
} }