36#include <com/sun/star/rendering/TexturingMode.hpp>
37#include <rtl/math.hxx>
40#include <parametricpolypolygon.hxx>
53 typedef std::shared_ptr< Gdiplus::PathGradientBrush > PathGradientBrushSharedPtr;
56 const ::canvas::ParametricPolyPolygon::Values& ,
57 const std::vector< Gdiplus::Color >& rColors,
58 const std::vector< Gdiplus::REAL >& rStops,
60 const rendering::Texture& texture )
65 Gdiplus::LinearGradientBrush aBrush(
73 aBrush.SetInterpolationColors(rColors.data(),
79 Gdiplus::SolidBrush aBackgroundBrush( rColors[0] );
80 rGraphics->FillPath( &aBackgroundBrush, rFillPath.get() );
89 ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
90 texture.AffineTransform );
97 aLeftTop *= aTextureTransform;
98 aLeftBottom *= aTextureTransform;
99 aRightTop *= aTextureTransform;
100 aRightBottom*= aTextureTransform;
102 Gdiplus::RectF aBounds;
103 rFillPath->GetBounds( &aBounds );
108 ::basegfx::utils::infiniteLineFromParallelogram( aLeftTop,
115 const double nDiagonalLength(
116 hypot( aBounds.Width,
126 aDirection = ::basegfx::getNormalizedPerpendicular( aDirection );
129 const ::basegfx::B2DPoint aHalfPlaneLeftTop( (aLeftTop + aRightTop) * 0.5 );
130 const ::basegfx::B2DPoint aHalfPlaneLeftBottom( (aLeftBottom + aRightBottom) * 0.5 );
131 const ::basegfx::B2DPoint aHalfPlaneRightTop( aRightTop + aDirection );
132 const ::basegfx::B2DPoint aHalfPlaneRightBottom( aRightBottom + aDirection );
134 Gdiplus::GraphicsPath aSolidFillPath;
135 aSolidFillPath.AddLine(
static_cast<Gdiplus::REAL
>(aHalfPlaneLeftTop.getX()),
136 static_cast<Gdiplus::REAL
>(aHalfPlaneLeftTop.getY()),
137 static_cast<Gdiplus::REAL
>(aHalfPlaneRightTop.getX()),
138 static_cast<Gdiplus::REAL
>(aHalfPlaneRightTop.getY()) );
139 aSolidFillPath.AddLine(
static_cast<Gdiplus::REAL
>(aHalfPlaneRightBottom.getX()),
140 static_cast<Gdiplus::REAL
>(aHalfPlaneRightBottom.getY()),
141 static_cast<Gdiplus::REAL
>(aHalfPlaneLeftBottom.getX()),
142 static_cast<Gdiplus::REAL
>(aHalfPlaneLeftBottom.getY()) );
143 aSolidFillPath.CloseFigure();
147 if( Gdiplus::Ok != rGraphics->SetClip( rFillPath.get(),
148 Gdiplus::CombineModeIntersect ) )
153 Gdiplus::SolidBrush aBackgroundBrush2( rColors.back() );
154 rGraphics->FillPath( &aBackgroundBrush2, &aSolidFillPath );
159 Gdiplus::GraphicsPath aClipPath;
160 aClipPath.AddLine(
static_cast<Gdiplus::REAL
>(aLeftTop.getX()),
161 static_cast<Gdiplus::REAL
>(aLeftTop.getY()),
162 static_cast<Gdiplus::REAL
>(aRightTop.getX()),
163 static_cast<Gdiplus::REAL
>(aRightTop.getY()) );
164 aClipPath.AddLine(
static_cast<Gdiplus::REAL
>(aRightBottom.getX()),
165 static_cast<Gdiplus::REAL
>(aRightBottom.getY()),
166 static_cast<Gdiplus::REAL
>(aLeftBottom.getX()),
167 static_cast<Gdiplus::REAL
>(aLeftBottom.getY()) );
168 aClipPath.CloseFigure();
172 if( Gdiplus::Ok != rGraphics->SetClip( &aClipPath,
173 Gdiplus::CombineModeIntersect ) )
179 Gdiplus::Matrix aMatrix;
181 texture.AffineTransform );
182 aBrush.SetTransform( &aMatrix );
184 rGraphics->FillRectangle( &aBrush, aBounds );
189 int numColorSteps(
const Gdiplus::Color& rColor1,
const Gdiplus::Color& rColor2 )
192 std::abs( rColor1.GetRed() - rColor2.GetRed() ),
194 std::abs( rColor1.GetGreen() - rColor2.GetGreen() ),
195 std::abs( rColor1.GetBlue() - rColor2.GetBlue() ) ) );
198 bool fillPolygonalGradient( const ::canvas::ParametricPolyPolygon::Values& rValues,
199 const std::vector< Gdiplus::Color >& rColors,
200 const std::vector< Gdiplus::REAL >& rStops,
203 const rendering::ViewState& viewState,
204 const rendering::RenderState& renderState,
205 const rendering::Texture& texture )
210 const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly );
212 PathGradientBrushSharedPtr pGradientBrush;
215 Gdiplus::SolidBrush aBackgroundBrush( rColors[0] );
216 rGraphics->FillPath( &aBackgroundBrush, pFillPath.get() );
218 Gdiplus::Matrix aMatrix;
223 if( !::rtl::math::approxEqual(rValues.mnAspectRatio,
239 if( Gdiplus::Ok != rGraphics->SetClip( pFillPath.get(),
240 Gdiplus::CombineModeIntersect ) )
246 const Gdiplus::SmoothingMode eOldAAMode( rGraphics->GetSmoothingMode() );
247 rGraphics->SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed );
255 for(
size_t i=0;
i<rColors.size()-1; ++
i )
256 nColorSteps += numColorSteps(rColors[i],rColors[i+1]);
258 const int nStepCount=
266 ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
267 texture.AffineTransform );
281 if( aOuterPoly.areControlPointsUsed() )
282 aOuterPoly = ::basegfx::utils::adaptiveSubdivideByAngle(aOuterPoly);
284 aInnerPoly = aOuterPoly;
296 const double nAspectRatio( rValues.mnAspectRatio );
297 if( nAspectRatio > 1.0 )
300 aInnerPolygonTransformMatrix.
scale( 1.0 - 1.0/nAspectRatio,
303 else if( nAspectRatio < 1.0 )
306 aInnerPolygonTransformMatrix.
scale( 0.0,
307 1.0 - nAspectRatio );
312 aInnerPolygonTransformMatrix.
scale( 0.0, 0.0 );
316 aInnerPolygonTransformMatrix *= aTextureTransform;
319 aInnerPoly.
transform( aInnerPolygonTransformMatrix );
321 Gdiplus::GraphicsPath aCurrPath;
322 Gdiplus::SolidBrush aFillBrush( rColors[0] );
323 const sal_uInt32 nNumPoints( aOuterPoly.count() );
325 for(
int i=1;
i<nStepCount; ++
i )
329 const double fT( i/
double(nStepCount) );
330 std::tie(nIndex,fAlpha)=aLerper.lerp(fT);
332 const Gdiplus::Color aFillColor(
337 aFillBrush.SetColor( aFillColor );
338 aCurrPath.Reset(); aCurrPath.StartFigure();
339 for(
unsigned int p=1;
p<nNumPoints; ++
p )
341 const ::basegfx::B2DPoint& rOuterPoint1( aOuterPoly.getB2DPoint(p-1) );
342 const ::basegfx::B2DPoint& rInnerPoint1( aInnerPoly.
getB2DPoint(p-1) );
343 const ::basegfx::B2DPoint& rOuterPoint2( aOuterPoly.getB2DPoint(p) );
344 const ::basegfx::B2DPoint& rInnerPoint2( aInnerPoly.
getB2DPoint(p) );
347 Gdiplus::REAL(fT*rInnerPoint1.getX() + (1-fT)*rOuterPoint1.getX()),
348 Gdiplus::REAL(fT*rInnerPoint1.getY() + (1-fT)*rOuterPoint1.getY()),
349 Gdiplus::REAL(fT*rInnerPoint2.getX() + (1-fT)*rOuterPoint2.getX()),
350 Gdiplus::REAL(fT*rInnerPoint2.getY() + (1-fT)*rOuterPoint2.getY()));
352 aCurrPath.CloseFigure();
354 rGraphics->FillPath( &aFillBrush, &aCurrPath );
358 rGraphics->SetSmoothingMode( eOldAAMode );
376 texture.AffineTransform );
379 pGradientPath->Transform( &aMatrix );
382 = std::make_shared<Gdiplus::PathGradientBrush>( pGradientPath.get() );
383 pGradientBrush->SetInterpolationColors( rColors.data(),
391 Gdiplus::PointF aCenterPoint(0, 0);
392 aMatrix.TransformPoints( &aCenterPoint );
393 pGradientBrush->SetCenterPoint( aCenterPoint );
395 const bool bTileX( texture.RepeatModeX != rendering::TexturingMode::CLAMP );
396 const bool bTileY( texture.RepeatModeY != rendering::TexturingMode::CLAMP );
398 if( bTileX && bTileY )
399 pGradientBrush->SetWrapMode( Gdiplus::WrapModeTile );
402 OSL_ENSURE( bTileY == bTileX,
403 "ParametricPolyPolygon::fillPolygonalGradient(): Cannot have repeat x and repeat y differ!" );
405 pGradientBrush->SetWrapMode( Gdiplus::WrapModeClamp );
409 rGraphics->FillPath( pGradientBrush.get(), pFillPath.get() );
412#if OSL_DEBUG_LEVEL > 0
413 Gdiplus::Pen aPen( Gdiplus::Color( 255, 255, 0, 0 ),
416 rGraphics->DrawRectangle( &aPen,
417 Gdiplus::RectF( 0.0f, 0.0f,
424 bool fillGradient( const ::canvas::ParametricPolyPolygon::Values& rValues,
425 const std::vector< Gdiplus::Color >& rColors,
426 const std::vector< Gdiplus::REAL >& rStops,
429 const rendering::ViewState& viewState,
430 const rendering::RenderState& renderState,
431 const rendering::Texture& texture )
433 switch( rValues.meType )
435 case ::canvas::ParametricPolyPolygon::GradientType::Linear:
436 fillLinearGradient( rGraphics,
444 case ::canvas::ParametricPolyPolygon::GradientType::Elliptical:
445 case ::canvas::ParametricPolyPolygon::GradientType::Rectangular:
446 fillPolygonalGradient( rValues,
458 "CanvasHelper::fillGradient(): Unexpected case" );
464 void fillBitmap(
const uno::Reference< rendering::XBitmap >& xBitmap,
467 const rendering::Texture& rTexture )
469 OSL_ENSURE( rTexture.RepeatModeX ==
470 rTexture.RepeatModeY,
471 "CanvasHelper::fillBitmap(): GDI+ cannot handle differing X/Y repeat mode." );
473 const bool bClamp( rTexture.RepeatModeX == rendering::TexturingMode::NONE &&
474 rTexture.RepeatModeY == rendering::TexturingMode::NONE );
476 const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() );
478 aBmpSize.Height != 0,
479 "CanvasHelper::fillBitmap(): zero-sized texture bitmap" );
491 if( ::rtl::math::approxEqual( rTexture.Alpha,
494 pBrush = std::make_shared<Gdiplus::TextureBrush>(
496 bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile );
500 Gdiplus::ImageAttributes aImgAttr;
508 Gdiplus::Rect aRect(0,0,
511 pBrush = std::make_shared<Gdiplus::TextureBrush>(
517 bClamp ? Gdiplus::WrapModeClamp : Gdiplus::WrapModeTile );
520 Gdiplus::Matrix aTextureTransform;
522 rTexture.AffineTransform );
526 pBrush->MultiplyTransform( &aTextureTransform );
527 pBrush->ScaleTransform(
static_cast< Gdiplus::REAL
>(1.0/aBmpSize.Width),
528 static_cast< Gdiplus::REAL
>(1.0/aBmpSize.Height) );
532 Gdiplus::Ok == rGraphics->FillPath( pBrush.get(),
534 "CanvasHelper::fillTexturedPolyPolygon(): GDI+ call failed" );
540 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
541 const rendering::ViewState& viewState,
542 const rendering::RenderState& renderState,
543 const uno::Sequence< rendering::Texture >& textures )
546 "CanvasHelper::fillTexturedPolyPolygon: polygon is NULL");
548 "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
566 const ::canvas::ParametricPolyPolygon::Values& rValues(
569 OSL_ASSERT(rValues.maColors.getLength() == rValues.maStops.getLength()
570 && rValues.maColors.getLength() > 1);
572 std::vector< Gdiplus::Color > aColors(rValues.maColors.getLength());
573 std::transform(&rValues.maColors[0],
574 &rValues.maColors[0]+rValues.maColors.getLength(),
576 [](
const uno::Sequence< double >& aDoubleSequence) { return tools::sequenceToArgb(aDoubleSequence); } );
577 std::vector< Gdiplus::REAL > aStops;
582 fillGradient( rValues,
592 else if( textures[0].
Bitmap.is() )
596 fillBitmap( textures[0].
Bitmap,
604 return uno::Reference< rendering::XCachedPrimitive >(
nullptr);
void scale(double fX, double fY)
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
void transform(const basegfx::B2DHomMatrix &rMatrix)
Values getValues() const
Query all defining values of this object atomically.
css::uno::Reference< css::rendering::XCachedPrimitive > fillTexturedPolyPolygon(const css::rendering::XCanvas *pCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, const css::uno::Sequence< css::rendering::Texture > &textures)
GraphicsProviderSharedPtr mpGraphicsProvider
Provides the Gdiplus::Graphics to render into.
void setupGraphicsState(GraphicsSharedPtr const &rGraphics, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
#define ENSURE_OR_THROW(c, m)
#define ENSURE_ARG_OR_THROW(c, m)
ValueType lerp(const ValueType &rFrom, const ValueType &rTo, double t)
DstType sequenceToContainer(const css::uno::Sequence< SrcType > &i_Sequence)
std::shared_ptr< ::cppcanvas::Bitmap > BitmapSharedPtr
std::shared_ptr< Gdiplus::Graphics > GraphicsSharedPtr
std::shared_ptr< Gdiplus::GraphicsPath > GraphicsPathSharedPtr
std::shared_ptr< Gdiplus::TextureBrush > TextureBrushSharedPtr
css::drawing::Direction3D aDirection