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