1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/rendering/XCanvas.hpp>
23 #include <sal/types.h>
25 #include <basegfx/range/b2drectangle.hxx>
26 #include <basegfx/utils/canvastools.hxx>
27 #include <basegfx/polygon/b2dpolypolygon.hxx>
28 #include <basegfx/polygon/b2dpolypolygontools.hxx>
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <canvas/canvastools.hxx>
31 #include <sal/log.hxx>
33 #include "cachedprimitivebase.hxx"
34 #include "polypolyaction.hxx"
35 #include <outdevstate.hxx>
37 #include "mtftools.hxx"
40 using namespace ::com::sun::star
;
42 namespace cppcanvas::internal
46 class PolyPolyAction
: public CachedPrimitiveBase
49 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
50 const CanvasSharedPtr
&,
54 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
55 const CanvasSharedPtr
&,
61 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
62 const Subset
& rSubset
) const override
;
64 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
65 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
66 const Subset
& rSubset
) const override
;
68 virtual sal_Int32
getActionCount() const override
;
72 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
73 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
75 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
76 const ::basegfx::B2DRange maBounds
;
77 const CanvasSharedPtr mpCanvas
;
79 // stroke color is now implicit: the maState.DeviceColor member
80 rendering::RenderState maState
;
82 uno::Sequence
< double > maFillColor
;
85 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
86 const CanvasSharedPtr
& rCanvas
,
87 const OutDevState
& rState
,
90 CachedPrimitiveBase( rCanvas
, false ),
91 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
92 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
95 tools::initRenderState(maState
,rState
);
98 maFillColor
= rState
.fillColor
;
101 maState
.DeviceColor
= rState
.lineColor
;
104 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
105 const CanvasSharedPtr
& rCanvas
,
106 const OutDevState
& rState
,
109 int nTransparency
) :
110 CachedPrimitiveBase( rCanvas
, false ),
111 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
112 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
115 tools::initRenderState(maState
,rState
);
119 maFillColor
= rState
.fillColor
;
121 if( maFillColor
.getLength() < 4 )
122 maFillColor
.realloc( 4 );
124 // TODO(F1): Color management
125 // adapt fill color transparency
126 maFillColor
.getArray()[3] = 1.0 - nTransparency
/ 100.0;
131 maState
.DeviceColor
= rState
.lineColor
;
133 if( maState
.DeviceColor
.getLength() < 4 )
134 maState
.DeviceColor
.realloc( 4 );
136 // TODO(F1): Color management
137 // adapt fill color transparency
138 maState
.DeviceColor
.getArray()[3] = 1.0 - nTransparency
/ 100.0;
142 bool PolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
143 const ::basegfx::B2DHomMatrix
& rTransformation
) const
145 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
146 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
148 rendering::RenderState
aLocalState( maState
);
149 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
151 if( maFillColor
.hasElements() )
153 // TODO(E3): Use DBO's finalizer here,
154 // fillPolyPolygon() might throw
155 const uno::Sequence
< double > aTmpColor( aLocalState
.DeviceColor
);
156 aLocalState
.DeviceColor
= maFillColor
;
158 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillPolyPolygon( mxPolyPoly
,
159 mpCanvas
->getViewState(),
162 aLocalState
.DeviceColor
= aTmpColor
;
165 if( aLocalState
.DeviceColor
.hasElements() )
167 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->drawPolyPolygon( mxPolyPoly
,
168 mpCanvas
->getViewState(),
175 bool PolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
176 const Subset
& rSubset
) const
178 // TODO(F1): Split up poly-polygon into polygons, or even
179 // line segments, when subsets are requested.
181 // polygon only contains a single action, fail if subset
182 // requests different range
183 if( rSubset
.mnSubsetBegin
!= 0 ||
184 rSubset
.mnSubsetEnd
!= 1 )
187 return CachedPrimitiveBase::render( rTransformation
);
190 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
192 rendering::RenderState
aLocalState( maState
);
193 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
195 return tools::calcDevicePixelBounds(
197 mpCanvas
->getViewState(),
201 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
202 const Subset
& rSubset
) const
204 // TODO(F1): Split up poly-polygon into polygons, or even
205 // line segments, when subsets are requested.
207 // polygon only contains a single action, empty bounds
208 // if subset requests different range
209 if( rSubset
.mnSubsetBegin
!= 0 ||
210 rSubset
.mnSubsetEnd
!= 1 )
211 return ::basegfx::B2DRange();
213 return getBounds( rTransformation
);
216 sal_Int32
PolyPolyAction::getActionCount() const
218 // TODO(F1): Split up poly-polygon into polygons, or even
219 // line segments, when subsets are requested.
224 class TexturedPolyPolyAction
: public CachedPrimitiveBase
227 TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
228 const CanvasSharedPtr
& rCanvas
,
229 const OutDevState
& rState
,
230 const rendering::Texture
& rTexture
);
232 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
233 const Subset
& rSubset
) const override
;
235 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
236 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
237 const Subset
& rSubset
) const override
;
239 virtual sal_Int32
getActionCount() const override
;
242 using Action::render
;
243 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
244 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
246 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
247 const ::basegfx::B2DRectangle maBounds
;
248 const CanvasSharedPtr mpCanvas
;
250 // stroke color is now implicit: the maState.DeviceColor member
251 rendering::RenderState maState
;
252 const rendering::Texture maTexture
;
255 TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
256 const CanvasSharedPtr
& rCanvas
,
257 const OutDevState
& rState
,
258 const rendering::Texture
& rTexture
) :
259 CachedPrimitiveBase( rCanvas
, true ),
260 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
261 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
263 maTexture( rTexture
)
265 tools::initRenderState(maState
,rState
);
268 bool TexturedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
269 const ::basegfx::B2DHomMatrix
& rTransformation
) const
271 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
272 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
274 rendering::RenderState
aLocalState( maState
);
275 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
277 uno::Sequence
< rendering::Texture
> aSeq
{ maTexture
};
279 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly
,
280 mpCanvas
->getViewState(),
286 bool TexturedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
287 const Subset
& rSubset
) const
289 // TODO(F1): Split up poly-polygon into polygons, or even
290 // line segments, when subsets are requested.
292 // polygon only contains a single action, fail if subset
293 // requests different range
294 if( rSubset
.mnSubsetBegin
!= 0 ||
295 rSubset
.mnSubsetEnd
!= 1 )
298 return CachedPrimitiveBase::render( rTransformation
);
301 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
303 rendering::RenderState
aLocalState( maState
);
304 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
306 return tools::calcDevicePixelBounds(
308 mpCanvas
->getViewState(),
312 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
313 const Subset
& rSubset
) const
315 // TODO(F1): Split up poly-polygon into polygons, or even
316 // line segments, when subsets are requested.
318 // polygon only contains a single action, empty bounds
319 // if subset requests different range
320 if( rSubset
.mnSubsetBegin
!= 0 ||
321 rSubset
.mnSubsetEnd
!= 1 )
322 return ::basegfx::B2DRange();
324 return getBounds( rTransformation
);
327 sal_Int32
TexturedPolyPolyAction::getActionCount() const
329 // TODO(F1): Split up poly-polygon into polygons, or even
330 // line segments, when subsets are requested.
335 class StrokedPolyPolyAction
: public CachedPrimitiveBase
338 StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
339 const CanvasSharedPtr
& rCanvas
,
340 const OutDevState
& rState
,
341 rendering::StrokeAttributes aStrokeAttributes
);
343 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
344 const Subset
& rSubset
) const override
;
346 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
347 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
348 const Subset
& rSubset
) const override
;
350 virtual sal_Int32
getActionCount() const override
;
353 using Action::render
;
354 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
355 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
357 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
358 const ::basegfx::B2DRectangle maBounds
;
359 const CanvasSharedPtr mpCanvas
;
360 rendering::RenderState maState
;
361 const rendering::StrokeAttributes maStrokeAttributes
;
364 StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
365 const CanvasSharedPtr
& rCanvas
,
366 const OutDevState
& rState
,
367 rendering::StrokeAttributes aStrokeAttributes
) :
368 CachedPrimitiveBase( rCanvas
, false ),
369 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
370 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
372 maStrokeAttributes(std::move( aStrokeAttributes
))
374 tools::initRenderState(maState
,rState
);
375 maState
.DeviceColor
= rState
.lineColor
;
378 bool StrokedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
379 const ::basegfx::B2DHomMatrix
& rTransformation
) const
381 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
382 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
384 rendering::RenderState
aLocalState( maState
);
385 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
387 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->strokePolyPolygon( mxPolyPoly
,
388 mpCanvas
->getViewState(),
390 maStrokeAttributes
);
394 bool StrokedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
395 const Subset
& rSubset
) const
397 // TODO(F1): Split up poly-polygon into polygons, or even
398 // line segments, when subsets are requested.
400 // polygon only contains a single action, fail if subset
401 // requests different range
402 if( rSubset
.mnSubsetBegin
!= 0 ||
403 rSubset
.mnSubsetEnd
!= 1 )
406 return CachedPrimitiveBase::render( rTransformation
);
409 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
411 rendering::RenderState
aLocalState( maState
);
412 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
414 return tools::calcDevicePixelBounds(
416 mpCanvas
->getViewState(),
420 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
421 const Subset
& rSubset
) const
423 // TODO(F1): Split up poly-polygon into polygons, or even
424 // line segments, when subsets are requested.
426 // polygon only contains a single action, empty bounds
427 // if subset requests different range
428 if( rSubset
.mnSubsetBegin
!= 0 ||
429 rSubset
.mnSubsetEnd
!= 1 )
430 return ::basegfx::B2DRange();
432 return getBounds( rTransformation
);
435 sal_Int32
StrokedPolyPolyAction::getActionCount() const
437 // TODO(F1): Split up poly-polygon into polygons, or even
438 // line segments, when subsets are requested.
443 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
444 const CanvasSharedPtr
& rCanvas
,
445 const OutDevState
& rState
)
447 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
448 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
449 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
450 rState
.isFillColorSet
,
451 rState
.isLineColorSet
);
454 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
455 const CanvasSharedPtr
& rCanvas
,
456 const OutDevState
& rState
,
457 const rendering::Texture
& rTexture
)
459 return std::make_shared
<TexturedPolyPolyAction
>( rPoly
, rCanvas
, rState
, rTexture
);
462 std::shared_ptr
<Action
> PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
463 const CanvasSharedPtr
& rCanvas
,
464 const OutDevState
& rState
)
466 OSL_ENSURE( rState
.isLineColorSet
,
467 "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" );
469 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
471 rState
.isLineColorSet
);
474 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
475 const CanvasSharedPtr
& rCanvas
,
476 const OutDevState
& rState
,
477 const rendering::StrokeAttributes
& rStrokeAttributes
)
479 OSL_ENSURE( rState
.isLineColorSet
,
480 "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" );
481 return std::make_shared
<StrokedPolyPolyAction
>( rPoly
, rCanvas
, rState
, rStrokeAttributes
);
484 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
485 const CanvasSharedPtr
& rCanvas
,
486 const OutDevState
& rState
,
489 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
490 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
491 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
492 rState
.isFillColorSet
,
493 rState
.isLineColorSet
,
499 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */