35#include <com/sun/star/rendering/TexturingMode.hpp>
36#include <rtl/math.hxx>
45#include <parametricpolypolygon.hxx>
59 const ::Point& rPosPixel,
60 const ::Size& rNextTileX,
61 const ::Size& rNextTileY,
64 const ::Size& rTileSize,
71 for( nY=0; nY < nTilesY; ++nY )
73 aCurrPos.setX( rPosPixel.X() + nY*rNextTileY.Width() );
74 aCurrPos.setY( rPosPixel.Y() + nY*rNextTileY.Height() );
76 for( nX=0; nX < nTilesX; ++nX )
80 bRet |= rGraphic.
Draw(rOutDev,
85 aCurrPos.AdjustX(rNextTileX.Width() );
86 aCurrPos.AdjustY(rNextTileX.Height() );
100 const ::basegfx::B2DHomMatrix& rTextureTransform,
101 const ::tools::Rectangle& rBounds,
102 unsigned int nStepCount,
103 const ::canvas::ParametricPolyPolygon::Values& rValues,
104 const std::vector< ::Color >& rColors )
115 aLeftTop *= rTextureTransform;
116 aLeftBottom *= rTextureTransform;
117 aRightTop *= rTextureTransform;
118 aRightBottom*= rTextureTransform;
121 const ::basegfx::B2DVector aBoundRectDiagonal(
124 const double nDiagonalLength( aBoundRectDiagonal.getLength() );
138 ::basegfx::utils::infiniteLineFromParallelogram( aLeftTop,
155 if( rColors.size() == 2 && rValues.maStops.size() == 2 && rValues.maStops[0] == 0 && rValues.maStops[1] == 1)
160 aLeftBottom -= 2.0*nDiagonalLength*
aDirection;
162 aRightBottom += 2.0*nDiagonalLength*
aDirection;
163 Gradient vclGradient( css::awt::GradientStyle_LINEAR, rColors[ 0 ], rColors[ 1 ] );
165 aTempPoly[0] = ::Point( ::basegfx::fround( aLeftTop.getX() ),
166 ::basegfx::fround( aLeftTop.getY() ) );
167 aTempPoly[1] = ::Point( ::basegfx::fround( aRightTop.getX() ),
168 ::basegfx::fround( aRightTop.getY() ) );
169 aTempPoly[2] = ::Point( ::basegfx::fround( aRightBottom.getX() ),
170 ::basegfx::fround( aRightBottom.getY() ) );
171 aTempPoly[3] = ::Point( ::basegfx::fround( aLeftBottom.getX() ),
172 ::basegfx::fround( aLeftBottom.getY() ) );
173 aTempPoly[4] = aTempPoly[0];
178 if( rColors.size() == 3 && rColors[ 0 ] == rColors[ 2 ]
179 && rValues.maStops.size() == 3 && rValues.maStops[0] == 0
180 && rValues.maStops[1] == 0.5 && rValues.maStops[2] == 1)
185 aLeftBottom -= 2.0*nDiagonalLength*
aDirection;
187 aRightBottom += 2.0*nDiagonalLength*
aDirection;
188 Gradient vclGradient( css::awt::GradientStyle_AXIAL, rColors[ 1 ], rColors[ 0 ] );
190 aTempPoly[0] = ::Point( ::basegfx::fround( aLeftTop.getX() ),
191 ::basegfx::fround( aLeftTop.getY() ) );
192 aTempPoly[1] = ::Point( ::basegfx::fround( aRightTop.getX() ),
193 ::basegfx::fround( aRightTop.getY() ) );
194 aTempPoly[2] = ::Point( ::basegfx::fround( aRightBottom.getX() ),
195 ::basegfx::fround( aRightBottom.getY() ) );
196 aTempPoly[3] = ::Point( ::basegfx::fround( aLeftBottom.getX() ),
197 ::basegfx::fround( aLeftBottom.getY() ) );
198 aTempPoly[4] = aTempPoly[0];
214 OSL_ENSURE( nStepCount >= 3,
215 "fillLinearGradient(): stepcount smaller than 3" );
227 const ::basegfx::B2DPoint& rPoint1( aLeftTop - 2.0*nDiagonalLength*aDirection );
228 aTempPoly[1] = ::Point( ::basegfx::fround( rPoint1.getX() ),
229 ::basegfx::fround( rPoint1.getY() ) );
231 const ::basegfx::B2DPoint& rPoint2( aLeftBottom - 2.0*nDiagonalLength*aDirection );
232 aTempPoly[2] = ::Point( ::basegfx::fround( rPoint2.getX() ),
233 ::basegfx::fround( rPoint2.getY() ) );
242 if( (rColors.size() % 2) != (nStepCount % 2) )
251 for(
unsigned int i=0;
i<nStepCount-1; ++
i )
255 std::tie(nIndex,fAlpha)=aLerper.lerp(
double(i)/nStepCount);
264 aTempPoly[0] = aTempPoly[4] = aTempPoly[1];
265 aTempPoly[3] = aTempPoly[2];
272 const ::basegfx::B2DPoint& rPoint3(
273 (nStepCount - i-1)/
double(nStepCount)*aLeftTop +
274 (i+1)/
double(nStepCount)*aRightTop );
275 aTempPoly[1] = ::Point( ::basegfx::fround( rPoint3.getX() ),
276 ::basegfx::fround( rPoint3.getY() ) );
278 const ::basegfx::B2DPoint& rPoint4(
279 (nStepCount - i-1)/
double(nStepCount)*aLeftBottom +
280 (i+1)/
double(nStepCount)*aRightBottom );
281 aTempPoly[2] = ::Point( ::basegfx::fround( rPoint4.getX() ),
282 ::basegfx::fround( rPoint4.getY() ) );
293 aTempPoly[0] = aTempPoly[4] = aTempPoly[1];
294 aTempPoly[3] = aTempPoly[2];
299 const ::basegfx::B2DPoint& rPoint3( aRightTop + 2.0*nDiagonalLength*aDirection );
300 aTempPoly[0] = aTempPoly[4] = ::Point( ::basegfx::fround( rPoint3.getX() ),
301 ::basegfx::fround( rPoint3.getY() ) );
303 const ::basegfx::B2DPoint& rPoint4( aRightBottom + 2.0*nDiagonalLength*aDirection );
304 aTempPoly[3] = ::Point( ::basegfx::fround( rPoint4.getX() ),
305 ::basegfx::fround( rPoint4.getY() ) );
313 const ::basegfx::B2DHomMatrix& rTextureTransform,
314 const ::tools::Rectangle& rBounds,
315 unsigned int nStepCount,
316 const ::canvas::ParametricPolyPolygon::Values& rValues,
317 const std::vector< ::Color >& rColors )
319 const ::basegfx::B2DPolygon& rGradientPoly( rValues.maGradientPoly );
322 "fillPolygonalGradient(): polygon without area given" );
333 if( aOuterPoly.areControlPointsUsed() )
334 aOuterPoly = ::basegfx::utils::adaptiveSubdivideByAngle(aOuterPoly);
336 aInnerPoly = aOuterPoly;
341 aOuterPoly.
transform( rTextureTransform );
356 const double nAspectRatio( rValues.mnAspectRatio );
357 if( nAspectRatio > 1.0 )
360 aInnerPolygonTransformMatrix.
scale( 1.0 - 1.0/nAspectRatio,
363 else if( nAspectRatio < 1.0 )
366 aInnerPolygonTransformMatrix.
scale( 0.0,
367 1.0 - nAspectRatio );
372 aInnerPolygonTransformMatrix.
scale( 0.0, 0.0 );
376 aInnerPolygonTransformMatrix *= rTextureTransform;
379 aInnerPoly.
transform( aInnerPolygonTransformMatrix );
382 const sal_uInt32 nNumPoints( aOuterPoly.count() );
412 for(
unsigned int i=1,p;
i<nStepCount; ++
i )
414 const double fT( i/
double(nStepCount) );
418 std::tie(nIndex,fAlpha)=aLerper.lerp(fT);
429 for( p=0;
p<nNumPoints; ++
p )
431 const ::basegfx::B2DPoint& rOuterPoint( aOuterPoly.getB2DPoint(p) );
432 const ::basegfx::B2DPoint& rInnerPoint( aInnerPoly.
getB2DPoint(p) );
434 aTempPoly[
static_cast<sal_uInt16
>(
p)] = ::Point(
436 basegfx::fround( fT*rInnerPoint.getY() + (1-fT)*rOuterPoint.getY() ) );
440 aTempPoly[
static_cast<sal_uInt16
>(
p)] = aTempPoly[0];
451 const ::canvas::ParametricPolyPolygon::Values& rValues,
452 const std::vector< ::Color >& rColors,
453 const ::basegfx::B2DHomMatrix& rTextureTransform,
454 const ::tools::Rectangle& rBounds,
455 unsigned int nStepCount )
457 switch( rValues.meType )
459 case ::canvas::ParametricPolyPolygon::GradientType::Linear:
460 fillLinearGradient( rOutDev,
468 case ::canvas::ParametricPolyPolygon::GradientType::Elliptical:
469 case ::canvas::ParametricPolyPolygon::GradientType::Rectangular:
470 fillPolygonalGradient( rOutDev,
480 "CanvasHelper::doGradientFill(): Unexpected case" );
484 int numColorSteps( const ::Color& rColor1, const ::Color& rColor2 )
487 std::abs( rColor1.GetRed() - rColor2.GetRed() ),
489 std::abs( rColor1.GetGreen() - rColor2.GetGreen() ),
490 std::abs( rColor1.GetBlue() - rColor2.GetBlue() ) ) );
495 const ::canvas::ParametricPolyPolygon::Values& rValues,
496 const std::vector< ::Color >& rColors,
497 const ::tools::PolyPolygon& rPoly,
498 const rendering::ViewState& viewState,
499 const rendering::RenderState& renderState,
500 const rendering::Texture& texture,
511 for(
size_t i=0;
i<rColors.size()-1; ++
i )
512 nColorSteps += numColorSteps(rColors[i],rColors[i+1]);
515 const int nStepCount=
526 const ::tools::Rectangle aPolygonDeviceRectOrig(
527 rPoly.GetBoundRect() );
543 doGradientFill( rOutDev,
547 aPolygonDeviceRectOrig,
551 if( p2ndOutDev && nTransparency < 253 )
558 p2ndOutDev->
DrawRect( aPolygonDeviceRectOrig );
568 doGradientFill( rOutDev,
572 aPolygonDeviceRectOrig,
576 if( p2ndOutDev && nTransparency < 253 )
587#ifdef DEBUG_CANVAS_CANVASHELPER_TEXTUREFILL
604 aPoly2.transform( aTextureTransform );
615 const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon,
616 const rendering::ViewState& viewState,
617 const rendering::RenderState& renderState,
618 const uno::Sequence< rendering::Texture >& textures )
621 "CanvasHelper::fillPolyPolygon(): polygon is NULL");
623 "CanvasHelper::fillTexturedPolyPolygon: empty texture sequence");
631 ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon),
632 viewState, renderState ) );
646 const ::canvas::ParametricPolyPolygon::Values& rValues(
649 if( rValues.maColors.getLength() < 2 )
651 rendering::RenderState aTempState=renderState;
652 aTempState.DeviceColor = rValues.maColors[0];
657 std::vector< ::Color > aColors(rValues.maColors.getLength());
658 std::transform(&rValues.maColors[0],
659 &rValues.maColors[0]+rValues.maColors.getLength(),
661 [](
const uno::Sequence< double >& aColor) {
662 return vcl::unotools::stdColorSpaceSequenceToColor( aColor );
682 "CanvasHelper::fillTexturedPolyPolygon(): unknown parametric polygon encountered" );
685 else if( textures[0].
Bitmap.is() )
687 geometry::IntegerSize2D aBmpSize( textures[0].
Bitmap->getSize() );
690 aBmpSize.Height != 0,
691 "CanvasHelper::fillTexturedPolyPolygon(): zero-sized texture bitmap" );
695 const ::tools::Rectangle aPolygonDeviceRect(
696 aPolyPoly.GetBoundRect() );
710 ::basegfx::unotools::homMatrixFromAffineMatrix( aTextureTransform,
711 textures[0].AffineTransform );
713 aTotalTransform *= aTextureTransform;
715 const ::basegfx::B2DRectangle aRect(0.0, 0.0, 1.0, 1.0);
721 const ::tools::Rectangle aIntegerTextureDeviceRect(
724 if( bRectangularPolygon &&
725 aIntegerTextureDeviceRect == aPolygonDeviceRect )
727 rendering::RenderState aLocalState( renderState );
731 aScaleCorrection.
scale( 1.0/aBmpSize.Width,
732 1.0/aBmpSize.Height );
737 if( !::rtl::math::approxEqual( textures[0].Alpha,
741 aLocalState.DeviceColor.realloc(4);
742 double* pColor = aLocalState.DeviceColor.getArray();
746 pColor[3] = textures[0].Alpha;
773 aScaling.
scale( 1.0/aBmpSize.Width,
774 1.0/aBmpSize.Height );
776 aTotalTransform = aTextureTransform * aScaling;
777 aPureTotalTransform = aTextureTransform;
785 aTotalTransform *= aMatrix;
786 aPureTotalTransform *= aMatrix;
794 aTotalTransform.
decompose( aScale, aOutputPos, nRotate, nShearX );
799 if( ::basegfx::fTools::equalZero( nShearX ) )
813 const double nAngleInTenthOfDegrees (3600.0 - basegfx::rad2deg<10>(nRotate));
816 pGrfObj = std::make_shared<GraphicObject>( aBmpEx );
839 pGrfObj = std::make_shared<GraphicObject>( aBmpEx );
843 aScale.
setX( 1.0 ); aScale.
setY( 1.0 );
864 aNextTileX *= aPureTotalTransform;
865 aNextTileY *= aPureTotalTransform;
870 "CanvasHelper::fillTexturedPolyPolygon(): singular texture matrix" );
872 aInverseTextureTransform.invert();
887 aInverseTextureTransform );
898 const sal_Int32 nX1( ::canvas::tools::roundDown( aTextureSpacePolygonRect.
getMinX() ) );
899 const sal_Int32 nY1( ::canvas::tools::roundDown( aTextureSpacePolygonRect.
getMinY() ) );
900 const sal_Int32 nX2( ::canvas::tools::roundUp( aTextureSpacePolygonRect.
getMaxX() ) );
901 const sal_Int32 nY2( ::canvas::tools::roundUp( aTextureSpacePolygonRect.
getMaxY() ) );
902 const ::basegfx::B2DRectangle aSingleTextureRect(
911 aPureTotalTransform );
915 const ::Size aSz( ::basegfx::fround( aScale.
getX() * aBmpSize.Width ),
916 ::basegfx::fround( aScale.
getY() * aBmpSize.Height ) );
920 const ::Point aPt( textures[0].RepeatModeX == rendering::TexturingMode::NONE ?
921 ::basegfx::fround( aOutputPos.
getX() ) : aPtRepeat.X(),
922 textures[0].RepeatModeY == rendering::TexturingMode::NONE ?
923 ::basegfx::fround( aOutputPos.
getY() ) : aPtRepeat.Y() );
924 const sal_Int32 nTilesX( textures[0].RepeatModeX == rendering::TexturingMode::NONE ?
926 const sal_Int32 nTilesY( textures[0].RepeatModeX == rendering::TexturingMode::NONE ?
931 if( bRectangularPolygon )
944 if( !::rtl::math::approxEqual( textures[0].Alpha,
958 ::basegfx::fround( 255.0 * textures[0].Alpha ) ) );
962 textureFill( rOutDev,
975 r2ndOutDev.IntersectClipRegion( aPolygonDeviceRect );
976 textureFill( r2ndOutDev,
993 if( !::rtl::math::approxEqual( textures[0].Alpha,
1001 pVDev->SetOutputSizePixel( aPolygonDeviceRect.GetSize() );
1004 const ::Point aOutPos( aPt - aPolygonDeviceRect.TopLeft() );
1005 aPolyPoly.Translate( ::Point( -aPolygonDeviceRect.Left(),
1006 -aPolygonDeviceRect.Top() ) );
1010 pVDev->SetClipRegion( aPolyClipRegion );
1011 textureFill( *pVDev,
1023 const ::Point aEmptyPoint;
1025 pVDev->GetBitmapEx( aEmptyPoint,
1026 pVDev->GetOutputSizePixel() ) );
1029 ::basegfx::fround( 255.0*( 1.0 - textures[0].Alpha ) ) ) );
1030 AlphaMask aAlpha( pVDev->GetOutputSizePixel(),
1033 BitmapEx aOutputBmpEx( aContentBmp.GetBitmap(), aAlpha );
1048 textureFill( rOutDev,
1064 r2ndOutDev.IntersectClipRegion( aPolyClipRegion );
1065 textureFill( r2ndOutDev,
1083 return uno::Reference< rendering::XCachedPrimitive >(
nullptr);
void SetRotation(Degree10 nRotate10)
void SetAlpha(sal_uInt8 cAlpha)
bool Draw(OutputDevice &rOut, const Point &rPt, const Size &rSz, const GraphicAttr *pAttr=nullptr) const
void DrawBitmapEx(const Point &rDestPt, const BitmapEx &rBitmapEx)
void DrawRect(const tools::Rectangle &rRect)
void DrawPolygon(const tools::Polygon &rPoly)
void Push(vcl::PushFlags nFlags=vcl::PushFlags::ALL)
void DrawGradient(const tools::Rectangle &rRect, const Gradient &rGradient)
void DrawPolyPolygon(const tools::PolyPolygon &rPolyPoly)
void IntersectClipRegion(const tools::Rectangle &rRect)
bool decompose(B2DTuple &rScale, B2DTuple &rTranslate, double &rRotate, double &rShearX) const
void scale(double fX, double fY)
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
void transform(const basegfx::B2DHomMatrix &rMatrix)
B2DPoint getMinimum() const
Values getValues() const
Query all defining values of this object atomically.
OutDevProviderSharedPtr mpProtectedOutDevProvider
Rendering to this outdev preserves its state.
int setupOutDevState(const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState, ColorType eColorType) const
css::uno::Reference< css::rendering::XCachedPrimitive > fillTexturedPolyPolygon(const css::rendering::XCanvas *rCanvas, 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)
css::uno::Reference< css::rendering::XCachedPrimitive > drawBitmap(const css::rendering::XCanvas *rCanvas, const css::uno::Reference< css::rendering::XBitmap > &xBitmap, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
css::uno::Reference< css::rendering::XCachedPrimitive > drawBitmapModulated(const css::rendering::XCanvas *rCanvas, const css::uno::Reference< css::rendering::XBitmap > &xBitmap, const css::rendering::ViewState &viewState, const css::rendering::RenderState &renderState)
OutDevProviderSharedPtr mpOutDevProvider
Rendering to this outdev does not preserve its state.
OutDevProviderSharedPtr mp2ndOutDevProvider
Rendering to this outdev does not preserve its state.
css::uno::Reference< css::rendering::XCachedPrimitive > fillPolyPolygon(const css::rendering::XCanvas *rCanvas, const css::uno::Reference< css::rendering::XPolyPolygon2D > &xPolyPolygon, 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)
B2IRange fround(const B2DRange &rRange)
std::shared_ptr< GraphicObject > GraphicObjectSharedPtr
const css::uno::Sequence< css::uno::Sequence< double > > maColors
Gradient colors.
css::drawing::Direction3D aDirection