#i105937# Finalized gradient rework in dxcanvas

This commit is contained in:
thb
2010-01-20 11:55:37 +01:00
parent a63c7b9380
commit 2ced8e8176
3 changed files with 70 additions and 200 deletions

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 <cppuhelper/compbase6.hxx> #include <cppuhelper/compbase6.hxx>
@@ -62,7 +61,7 @@ namespace dxcanvas
{ {
typedef ::cppu::WeakComponentImplHelper6< ::com::sun::star::rendering::XCanvas, typedef ::cppu::WeakComponentImplHelper6< ::com::sun::star::rendering::XCanvas,
::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 > GraphicDeviceBase1_Base; ::com::sun::star::lang::XServiceName > GraphicDeviceBase1_Base;
@@ -119,7 +118,7 @@ namespace dxcanvas
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 > GraphicDeviceBase2_Base; ::com::sun::star::lang::XServiceName > GraphicDeviceBase2_Base;

View File

@@ -42,6 +42,8 @@
#include <basegfx/range/b2drectangle.hxx> #include <basegfx/range/b2drectangle.hxx>
#include <basegfx/numeric/ftools.hxx> #include <basegfx/numeric/ftools.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/matrix/b2dhommatrixtools.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx>
@@ -52,6 +54,8 @@
#include "dx_impltools.hxx" #include "dx_impltools.hxx"
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>
using namespace ::com::sun::star; using namespace ::com::sun::star;
@@ -62,11 +66,12 @@ namespace dxcanvas
{ {
typedef ::boost::shared_ptr< Gdiplus::PathGradientBrush > PathGradientBrushSharedPtr; typedef ::boost::shared_ptr< Gdiplus::PathGradientBrush > PathGradientBrushSharedPtr;
bool fillLinearGradient( GraphicsSharedPtr& rGraphics, bool fillLinearGradient( GraphicsSharedPtr& rGraphics,
const Gdiplus::Color& rColor1, const ::canvas::ParametricPolyPolygon::Values& rValues,
const Gdiplus::Color& rColor2, const std::vector< Gdiplus::Color >& rColors,
const GraphicsPathSharedPtr& rFillPath, const std::vector< REAL >& rStops,
const rendering::Texture& texture ) const GraphicsPathSharedPtr& rFillPath,
const rendering::Texture& texture )
{ {
// setup a linear gradient with two colors // setup a linear gradient with two colors
// --------------------------------------- // ---------------------------------------
@@ -76,12 +81,16 @@ namespace dxcanvas
0.5f), 0.5f),
Gdiplus::PointF(1.0f, Gdiplus::PointF(1.0f,
0.5f), 0.5f),
rColor1, rColors[0],
rColor2 ); rColors[1] );
aBrush.SetInterpolationColors(&rColors[0],
&rStops[0],
rColors.size());
// render background color, as LinearGradientBrush does not // render background color, as LinearGradientBrush does not
// properly support the WrapModeClamp repeat mode // properly support the WrapModeClamp repeat mode
Gdiplus::SolidBrush aBackgroundBrush( rColor1 ); Gdiplus::SolidBrush aBackgroundBrush( rColors[0] );
rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() ); rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() );
// TODO(F2): This does not yet support other repeat modes // TODO(F2): This does not yet support other repeat modes
@@ -191,144 +200,10 @@ namespace dxcanvas
return true; return true;
} }
bool fillAxialGradient( GraphicsSharedPtr& rGraphics,
const Gdiplus::Color& rColor1,
const Gdiplus::Color& rColor2,
const GraphicsPathSharedPtr& rFillPath,
const rendering::Texture& texture )
{
// setup a linear gradient with three colors
// -----------------------------------------
Gdiplus::LinearGradientBrush aBrush(
Gdiplus::PointF(0.0f,
0.5f),
Gdiplus::PointF(1.0f,
0.5f),
rColor1,
rColor1 );
Gdiplus::Color aColors[] =
{
rColor1, // at 0.0
rColor2, // at 0.5
rColor1 // at 1.0
};
Gdiplus::REAL aPositions[] =
{
0.0,
0.5,
1.0
};
if( Gdiplus::Ok != aBrush.SetInterpolationColors( aColors,
aPositions,
sizeof( aPositions ) / sizeof(Gdiplus::REAL) ) )
{
return false;
}
// render background color, as LinearGradientBrush does not
// properly support the WrapModeClamp repeat mode
Gdiplus::SolidBrush aBackgroundBrush( rColor1 );
rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() );
// TODO(F2): This does not yet support other repeat modes
// except clamp, and probably also no multi-texturing
// calculate parallelogram of gradient in object space, extend
// top and bottom of it such that they cover the whole fill
// path bound area
::basegfx::B2DHomMatrix aTextureTransform;
::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
texture.AffineTransform );
::basegfx::B2DPoint aLeftTop( 0.0, 0.0 );
::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 );
::basegfx::B2DPoint aRightTop( 1.0, 0.0 );
::basegfx::B2DPoint aRightBottom( 1.0, 1.0 );
aLeftTop *= aTextureTransform;
aLeftBottom *= aTextureTransform;
aRightTop *= aTextureTransform;
aRightBottom*= aTextureTransform;
Gdiplus::RectF aBounds;
rFillPath->GetBounds( &aBounds, NULL, NULL );
// now, we potentially have to enlarge our gradient area
// atop and below the transformed [0,1]x[0,1] unit rect,
// for the gradient to fill the complete bound rect.
::basegfx::tools::infiniteLineFromParallelogram( aLeftTop,
aLeftBottom,
aRightTop,
aRightBottom,
tools::b2dRangeFromGdiPlusRectF( aBounds ) );
// generate clip polygon from the extended parallelogram
// (exploit the feature that distinct lines in a figure are
// automatically closed by a straight line)
Gdiplus::GraphicsPath aClipPath;
aClipPath.AddLine( static_cast<Gdiplus::REAL>(aLeftTop.getX()),
static_cast<Gdiplus::REAL>(aLeftTop.getY()),
static_cast<Gdiplus::REAL>(aRightTop.getX()),
static_cast<Gdiplus::REAL>(aRightTop.getY()) );
aClipPath.AddLine( static_cast<Gdiplus::REAL>(aRightBottom.getX()),
static_cast<Gdiplus::REAL>(aRightBottom.getY()),
static_cast<Gdiplus::REAL>(aLeftBottom.getX()),
static_cast<Gdiplus::REAL>(aLeftBottom.getY()) );
aClipPath.CloseFigure();
// limit output to a _single_ strip of the gradient (have to
// clip here, since GDI+ wrapmode clamp does not work here)
if( Gdiplus::Ok != rGraphics->SetClip( rFillPath.get(),
Gdiplus::CombineModeIntersect ) )
{
return false;
}
if( Gdiplus::Ok != rGraphics->SetClip( &aClipPath,
Gdiplus::CombineModeIntersect ) )
{
return false;
}
// now, finally, output the gradient
Gdiplus::Matrix aMatrix;
tools::gdiPlusMatrixFromAffineMatrix2D( aMatrix,
texture.AffineTransform );
aBrush.SetTransform( &aMatrix );
rGraphics->FillRectangle( &aBrush, aBounds );
return true;
}
PathGradientBrushSharedPtr createPathGradientBrush( const GraphicsPathSharedPtr& rGradientPath,
const Gdiplus::Color& rColor1,
const Gdiplus::Color& rColor2 )
{
PathGradientBrushSharedPtr pGradientBrush(
new Gdiplus::PathGradientBrush( rGradientPath.get() ) );
Gdiplus::Color aColors[] =
{
rColor1
};
INT nCount(1);
pGradientBrush->SetSurroundColors( aColors,
&nCount );
pGradientBrush->SetCenterColor( rColor2 );
return pGradientBrush;
}
bool fillPolygonalGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, bool fillPolygonalGradient( const ::canvas::ParametricPolyPolygon::Values& rValues,
const std::vector< Gdiplus::Color >& rColors,
const std::vector< REAL >& rStops,
GraphicsSharedPtr& rGraphics, GraphicsSharedPtr& rGraphics,
const Gdiplus::Color& rColor1,
const Gdiplus::Color& rColor2,
const GraphicsPathSharedPtr& rPath, const GraphicsPathSharedPtr& rPath,
const rendering::Texture& texture ) const rendering::Texture& texture )
{ {
@@ -351,7 +226,7 @@ namespace dxcanvas
PathGradientBrushSharedPtr pGradientBrush; PathGradientBrushSharedPtr pGradientBrush;
// fill background uniformly with end color // fill background uniformly with end color
Gdiplus::SolidBrush aBackgroundBrush( rColor1 ); Gdiplus::SolidBrush aBackgroundBrush( rColors[0] );
rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() ); rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() );
// scale focus according to aspect ratio: for wider-than-tall // scale focus according to aspect ratio: for wider-than-tall
@@ -391,12 +266,9 @@ namespace dxcanvas
// -------------------------------- // --------------------------------
// TODO(Q2): Unify step calculations with VCL canvas // TODO(Q2): Unify step calculations with VCL canvas
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() ) ) ) );
Gdiplus::Matrix aWorldTransformMatrix; Gdiplus::Matrix aWorldTransformMatrix;
rGraphics->GetTransform( &aWorldTransformMatrix ); rGraphics->GetTransform( &aWorldTransformMatrix );
@@ -409,17 +281,16 @@ namespace dxcanvas
static_cast<int>( hypot( aBounds.Width, aBounds.Height ) + 1.0 ) ); static_cast<int>( hypot( aBounds.Width, aBounds.Height ) + 1.0 ) );
// typical number for pixel of the same color (strip size) // typical number for pixel of the same color (strip size)
const int nStripSize( 2 ); const int nStripSize( nGradientSize < 50 ? 2 : 4 );
// use at least three steps, and at utmost the number of // use at least three steps, and at utmost the number of color
// color steps. // steps
const int nStepCount( const int nStepCount(
::std::max( ::std::max(
3, 3,
::std::min( ::std::min(
nGradientSize / nStripSize, nGradientSize / nStripSize,
nColorSteps ) ) + 1 ); nColorSteps ) ) );
Gdiplus::SolidBrush aFillBrush( rColor1 ); Gdiplus::SolidBrush aFillBrush( rColor1 );
Gdiplus::Matrix aGDIScaleMatrix; Gdiplus::Matrix aGDIScaleMatrix;
@@ -436,19 +307,17 @@ namespace dxcanvas
1.0 - 1.0/rValues.mnAspectRatio : 1.0 - 1.0/rValues.mnAspectRatio :
1.0 - rValues.mnAspectRatio ); 1.0 - rValues.mnAspectRatio );
basegfx::tools::KeyStopLerp aLerper(rValues.maStops);
for( int i=1; i<nStepCount; ++i ) for( int i=1; i<nStepCount; ++i )
{ {
// lerp color. Funnily, the straight-forward integer std::ptrdiff_t nIndex;
// lerp ((nStepCount - i)*val + i*val)/nStepCount gets double fAlpha;
// fully botched by MSVC, at least for anything that boost::tuples::tie(nIndex,fAlpha)=aLerper.lerp(double(i)/nStepCount);
// really inlines inlines (i.e. every compile without
// debug=t)
const double nFrac( (double)i/nStepCount );
const Gdiplus::Color aFillColor( const Gdiplus::Color aFillColor(
static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetRed() + nFrac*rColor2.GetRed() ), static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetRed(),rColors[nIndex+1].GetRed(),fAlpha) ),
static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetGreen() + nFrac*rColor2.GetGreen() ), static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetGreen(),rColors[nIndex+1].GetGreen(),fAlpha) ),
static_cast<BYTE>( (1.0 - nFrac)*rColor1.GetBlue() + nFrac*rColor2.GetBlue() ) ); static_cast<BYTE>( basegfx::tools::lerp(rColors[nIndex].GetBlue(),rColors[nIndex+1].GetBlue(),fAlpha) ) );
aFillBrush.SetColor( aFillColor ); aFillBrush.SetColor( aFillColor );
@@ -512,10 +381,11 @@ namespace dxcanvas
pGradientPath->Transform( &aMatrix ); pGradientPath->Transform( &aMatrix );
pGradientBrush = createPathGradientBrush( pGradientBrush.reset(
pGradientPath, new Gdiplus::PathGradientBrush( pGradientPath.get() ) );
rColor1, pGradientBrush->SetInterpolationColors( &rColors[0],
rColor2 ); &rStops[0],
rStops.size() );
// explicitely setup center point. Since the center of GDI+ // explicitely setup center point. Since the center of GDI+
// gradients are by default the _centroid_ of the path // gradients are by default the _centroid_ of the path
@@ -557,8 +427,8 @@ namespace dxcanvas
} }
bool fillGradient( const ::canvas::ParametricPolyPolygon::Values& rValues, bool fillGradient( const ::canvas::ParametricPolyPolygon::Values& rValues,
const Gdiplus::Color& rColor1, const std::vector< Gdiplus::Color >& rColors,
const Gdiplus::Color& rColor2, const std::vector< REAL >& rStops,
GraphicsSharedPtr& rGraphics, GraphicsSharedPtr& rGraphics,
const GraphicsPathSharedPtr& rPath, const GraphicsPathSharedPtr& rPath,
const rendering::Texture& texture ) const rendering::Texture& texture )
@@ -567,27 +437,20 @@ namespace dxcanvas
{ {
case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR: case ::canvas::ParametricPolyPolygon::GRADIENT_LINEAR:
fillLinearGradient( rGraphics, fillLinearGradient( rGraphics,
rColor1, rValues,
rColor2, rColors,
rStops,
rPath, rPath,
texture ); texture );
break; break;
case ::canvas::ParametricPolyPolygon::GRADIENT_AXIAL:
fillAxialGradient( rGraphics,
rColor1,
rColor2,
rPath,
texture );
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( rValues, fillPolygonalGradient( rValues,
rColors,
rStops,
rGraphics, rGraphics,
rColor1,
rColor2,
rPath, rPath,
texture ); texture );
break; break;
@@ -709,15 +572,24 @@ namespace dxcanvas
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 OSL_ASSERT(rValues.maColors.getLength() == rValues.maStops.getLength()
const Gdiplus::Color aColor1(tools::sequenceToArgb(rValues.maColors[0])); && rValues.maColors.getLength() > 1);
const Gdiplus::Color aColor2(tools::sequenceToArgb(rValues.maColors[rValues.maColors.getLength () - 1] ));
std::vector< Gdiplus::Color > aColors(rValues.maColors.getLength());
std::transform(&rValues.maColors[0],
&rValues.maColors[0]+rValues.maColors.getLength(),
aColors.begin(),
boost::bind(
&tools::sequenceToArgb,
_1));
std::vector< REAL > aStops;
comphelper::sequenceToContainer(aStops,rValues.maStops);
// TODO(E1): Return value // TODO(E1): Return value
// TODO(F1): FillRule // TODO(F1): FillRule
fillGradient( rValues, fillGradient( rValues,
aColor1, aColors,
aColor2, aStops,
pGraphics, pGraphics,
tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ), tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ),
textures[0] ); textures[0] );

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>
@@ -61,14 +60,14 @@
namespace dxcanvas namespace dxcanvas
{ {
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,
::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XPropertySet,
::com::sun::star::lang::XServiceName > WindowGraphicDeviceBase_Base; ::com::sun::star::lang::XServiceName > WindowGraphicDeviceBase_Base;
typedef ::canvas::BufferedGraphicDeviceBase< ::canvas::BaseMutexHelper< WindowGraphicDeviceBase_Base >, typedef ::canvas::BufferedGraphicDeviceBase< ::canvas::BaseMutexHelper< WindowGraphicDeviceBase_Base >,
SpriteDeviceHelper, SpriteDeviceHelper,
::osl::MutexGuard, ::osl::MutexGuard,