From 1837a267a2cf82b0152631e416d8be66c2adef25 Mon Sep 17 00:00:00 2001 From: thb Date: Fri, 16 Oct 2009 00:43:16 +0200 Subject: #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 --- cppcanvas/source/mtfrenderer/implrenderer.cxx | 369 +++++++++----------------- 1 file changed, 131 insertions(+), 238 deletions(-) (limited to 'cppcanvas/source/mtfrenderer/implrenderer.cxx') 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 #include -#include #include #include #include @@ -61,6 +60,7 @@ #include #include +#include #include #include #include @@ -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 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; } } -- cgit From 40ae7d9aca558a8ebfd3279b9bc96ec0e03bbd48 Mon Sep 17 00:00:00 2001 From: "Frank Schoenheit [fs]" Date: Fri, 29 Jan 2010 08:49:42 +0100 Subject: autorecovery: ENSURE_OR_RETURN => ENSURE_OR_RETURN_FALSE, added new ENSURE_OR_RETURN taking a return value --- cppcanvas/source/mtfrenderer/implrenderer.cxx | 30 +++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'cppcanvas/source/mtfrenderer/implrenderer.cxx') diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx index 8ea2ae453a97..0f51216b190e 100644 --- a/cppcanvas/source/mtfrenderer/implrenderer.cxx +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -1876,16 +1876,16 @@ namespace cppcanvas ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), aBmpEx ); - if( aFill.isTiling() ) - { - aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; - aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; - } - else - { - aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; - aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; - } + if( aFill.isTiling() ) + { + aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; + aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; + } + else + { + aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; + aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; + } ::PolyPolygon aPath; aFill.getPath( aPath ); @@ -2877,7 +2877,7 @@ namespace cppcanvas aSubset.mnSubsetEnd = ::std::min( aRangeBegin->mpAction->getActionCount(), nEndIndex - aRangeBegin->mnOrigIndex ); - ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, "ImplRenderer::forSubsetRange(): Invalid indices" ); rFunctor( *aRangeBegin, aSubset ); @@ -2893,7 +2893,7 @@ namespace cppcanvas nStartIndex - aRangeBegin->mnOrigIndex ); aSubset.mnSubsetEnd = aRangeBegin->mpAction->getActionCount(); - ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, "ImplRenderer::forSubsetRange(): Invalid indices" ); rFunctor( *aRangeBegin, aSubset ); @@ -2922,7 +2922,7 @@ namespace cppcanvas aSubset.mnSubsetBegin = 0; aSubset.mnSubsetEnd = nEndIndex - aRangeEnd->mnOrigIndex; - ENSURE_OR_RETURN( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, + ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0, "ImplRenderer::forSubsetRange(): Invalid indices" ); rFunctor( *aRangeEnd, aSubset ); @@ -2937,10 +2937,10 @@ namespace cppcanvas ActionVector::const_iterator& o_rRangeBegin, ActionVector::const_iterator& o_rRangeEnd ) const { - ENSURE_OR_RETURN( io_rStartIndex<=io_rEndIndex, + ENSURE_OR_RETURN_FALSE( io_rStartIndex<=io_rEndIndex, "ImplRenderer::getSubsetIndices(): invalid action range" ); - ENSURE_OR_RETURN( !maActions.empty(), + ENSURE_OR_RETURN_FALSE( !maActions.empty(), "ImplRenderer::getSubsetIndices(): no actions to render" ); const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex ); -- cgit From 1737f4d2fdba50a590f76631cd7ca7e762d18c35 Mon Sep 17 00:00:00 2001 From: thb Date: Mon, 18 Jan 2010 00:37:41 +0100 Subject: #i52325# #i108250# removed B3DGeometry, fixed gradient/fill bitmap * removed unused & broken B3DGeometry class * fixed bug in basegfx::tools::isRectangle for polygons with curves * fixed cairocanvas gradient and bitmap fill rendering * fixed vclcanvas bitmap fill rendering (not clipping properly) * added TextureMode::NONE, adapted all client code * fixed snafu in XGraphicDevice.idl, with missing include --- cppcanvas/source/mtfrenderer/implrenderer.cxx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'cppcanvas/source/mtfrenderer/implrenderer.cxx') diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx b/cppcanvas/source/mtfrenderer/implrenderer.cxx index daef89bf2905..2435cf0e77ec 100644 --- a/cppcanvas/source/mtfrenderer/implrenderer.cxx +++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx @@ -1767,16 +1767,16 @@ namespace cppcanvas ::vcl::unotools::xBitmapFromBitmapEx( rCanvas->getUNOCanvas()->getDevice(), aBmpEx ); - if( aFill.isTiling() ) - { - aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; - aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; - } - else - { - aTexture.RepeatModeX = rendering::TexturingMode::CLAMP; - aTexture.RepeatModeY = rendering::TexturingMode::CLAMP; - } + if( aFill.isTiling() ) + { + aTexture.RepeatModeX = rendering::TexturingMode::REPEAT; + aTexture.RepeatModeY = rendering::TexturingMode::REPEAT; + } + else + { + aTexture.RepeatModeX = rendering::TexturingMode::NONE; + aTexture.RepeatModeY = rendering::TexturingMode::NONE; + } ::PolyPolygon aPath; aFill.getPath( aPath ); -- cgit