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 <osl/diagnose.h>
32 #include <sal/log.hxx>
34 #include "cachedprimitivebase.hxx"
35 #include "polypolyaction.hxx"
36 #include <outdevstate.hxx>
38 #include "mtftools.hxx"
41 using namespace ::com::sun::star
;
43 namespace cppcanvas::internal
47 class PolyPolyAction
: public CachedPrimitiveBase
50 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
51 const CanvasSharedPtr
&,
55 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
56 const CanvasSharedPtr
&,
62 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
63 const Subset
& rSubset
) const override
;
65 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
66 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
67 const Subset
& rSubset
) const override
;
69 virtual sal_Int32
getActionCount() const override
;
73 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
74 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
76 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
77 const ::basegfx::B2DRange maBounds
;
78 const CanvasSharedPtr mpCanvas
;
80 // stroke color is now implicit: the maState.DeviceColor member
81 rendering::RenderState maState
;
83 uno::Sequence
< double > maFillColor
;
86 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
87 const CanvasSharedPtr
& rCanvas
,
88 const OutDevState
& rState
,
91 CachedPrimitiveBase( rCanvas
, false ),
92 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
93 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
96 tools::initRenderState(maState
,rState
);
99 maFillColor
= rState
.fillColor
;
102 maState
.DeviceColor
= rState
.lineColor
;
105 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
106 const CanvasSharedPtr
& rCanvas
,
107 const OutDevState
& rState
,
110 int nTransparency
) :
111 CachedPrimitiveBase( rCanvas
, false ),
112 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
113 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
116 tools::initRenderState(maState
,rState
);
120 maFillColor
= rState
.fillColor
;
122 if( maFillColor
.getLength() < 4 )
123 maFillColor
.realloc( 4 );
125 // TODO(F1): Color management
126 // adapt fill color transparency
127 maFillColor
.getArray()[3] = 1.0 - nTransparency
/ 100.0;
132 maState
.DeviceColor
= rState
.lineColor
;
134 if( maState
.DeviceColor
.getLength() < 4 )
135 maState
.DeviceColor
.realloc( 4 );
137 // TODO(F1): Color management
138 // adapt fill color transparency
139 maState
.DeviceColor
.getArray()[3] = 1.0 - nTransparency
/ 100.0;
143 bool PolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
144 const ::basegfx::B2DHomMatrix
& rTransformation
) const
146 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
147 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
149 rendering::RenderState
aLocalState( maState
);
150 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
152 if( maFillColor
.hasElements() )
154 // TODO(E3): Use DBO's finalizer here,
155 // fillPolyPolygon() might throw
156 const uno::Sequence
< double > aTmpColor( aLocalState
.DeviceColor
);
157 aLocalState
.DeviceColor
= maFillColor
;
159 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillPolyPolygon( mxPolyPoly
,
160 mpCanvas
->getViewState(),
163 aLocalState
.DeviceColor
= aTmpColor
;
166 if( aLocalState
.DeviceColor
.hasElements() )
168 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->drawPolyPolygon( mxPolyPoly
,
169 mpCanvas
->getViewState(),
176 bool PolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
177 const Subset
& rSubset
) const
179 // TODO(F1): Split up poly-polygon into polygons, or even
180 // line segments, when subsets are requested.
182 // polygon only contains a single action, fail if subset
183 // requests different range
184 if( rSubset
.mnSubsetBegin
!= 0 ||
185 rSubset
.mnSubsetEnd
!= 1 )
188 return CachedPrimitiveBase::render( rTransformation
);
191 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
193 rendering::RenderState
aLocalState( maState
);
194 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
196 return tools::calcDevicePixelBounds(
198 mpCanvas
->getViewState(),
202 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
203 const Subset
& rSubset
) const
205 // TODO(F1): Split up poly-polygon into polygons, or even
206 // line segments, when subsets are requested.
208 // polygon only contains a single action, empty bounds
209 // if subset requests different range
210 if( rSubset
.mnSubsetBegin
!= 0 ||
211 rSubset
.mnSubsetEnd
!= 1 )
212 return ::basegfx::B2DRange();
214 return getBounds( rTransformation
);
217 sal_Int32
PolyPolyAction::getActionCount() const
219 // TODO(F1): Split up poly-polygon into polygons, or even
220 // line segments, when subsets are requested.
225 class TexturedPolyPolyAction
: public CachedPrimitiveBase
228 TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
229 const CanvasSharedPtr
& rCanvas
,
230 const OutDevState
& rState
,
231 const rendering::Texture
& rTexture
);
233 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
234 const Subset
& rSubset
) const override
;
236 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
237 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
238 const Subset
& rSubset
) const override
;
240 virtual sal_Int32
getActionCount() const override
;
243 using Action::render
;
244 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
245 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
247 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
248 const ::basegfx::B2DRectangle maBounds
;
249 const CanvasSharedPtr mpCanvas
;
251 // stroke color is now implicit: the maState.DeviceColor member
252 rendering::RenderState maState
;
253 const rendering::Texture maTexture
;
256 TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
257 const CanvasSharedPtr
& rCanvas
,
258 const OutDevState
& rState
,
259 const rendering::Texture
& rTexture
) :
260 CachedPrimitiveBase( rCanvas
, true ),
261 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
262 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
264 maTexture( rTexture
)
266 tools::initRenderState(maState
,rState
);
269 bool TexturedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
270 const ::basegfx::B2DHomMatrix
& rTransformation
) const
272 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
273 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
275 rendering::RenderState
aLocalState( maState
);
276 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
278 uno::Sequence
< rendering::Texture
> aSeq
{ maTexture
};
280 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly
,
281 mpCanvas
->getViewState(),
287 bool TexturedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
288 const Subset
& rSubset
) const
290 // TODO(F1): Split up poly-polygon into polygons, or even
291 // line segments, when subsets are requested.
293 // polygon only contains a single action, fail if subset
294 // requests different range
295 if( rSubset
.mnSubsetBegin
!= 0 ||
296 rSubset
.mnSubsetEnd
!= 1 )
299 return CachedPrimitiveBase::render( rTransformation
);
302 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
304 rendering::RenderState
aLocalState( maState
);
305 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
307 return tools::calcDevicePixelBounds(
309 mpCanvas
->getViewState(),
313 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
314 const Subset
& rSubset
) const
316 // TODO(F1): Split up poly-polygon into polygons, or even
317 // line segments, when subsets are requested.
319 // polygon only contains a single action, empty bounds
320 // if subset requests different range
321 if( rSubset
.mnSubsetBegin
!= 0 ||
322 rSubset
.mnSubsetEnd
!= 1 )
323 return ::basegfx::B2DRange();
325 return getBounds( rTransformation
);
328 sal_Int32
TexturedPolyPolyAction::getActionCount() const
330 // TODO(F1): Split up poly-polygon into polygons, or even
331 // line segments, when subsets are requested.
336 class StrokedPolyPolyAction
: public CachedPrimitiveBase
339 StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
340 const CanvasSharedPtr
& rCanvas
,
341 const OutDevState
& rState
,
342 rendering::StrokeAttributes aStrokeAttributes
);
344 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
345 const Subset
& rSubset
) const override
;
347 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
348 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
349 const Subset
& rSubset
) const override
;
351 virtual sal_Int32
getActionCount() const override
;
354 using Action::render
;
355 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
356 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
358 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
359 const ::basegfx::B2DRectangle maBounds
;
360 const CanvasSharedPtr mpCanvas
;
361 rendering::RenderState maState
;
362 const rendering::StrokeAttributes maStrokeAttributes
;
365 StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
366 const CanvasSharedPtr
& rCanvas
,
367 const OutDevState
& rState
,
368 rendering::StrokeAttributes aStrokeAttributes
) :
369 CachedPrimitiveBase( rCanvas
, false ),
370 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
371 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
373 maStrokeAttributes(std::move( aStrokeAttributes
))
375 tools::initRenderState(maState
,rState
);
376 maState
.DeviceColor
= rState
.lineColor
;
379 bool StrokedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
380 const ::basegfx::B2DHomMatrix
& rTransformation
) const
382 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
383 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
385 rendering::RenderState
aLocalState( maState
);
386 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
388 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->strokePolyPolygon( mxPolyPoly
,
389 mpCanvas
->getViewState(),
391 maStrokeAttributes
);
395 bool StrokedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
396 const Subset
& rSubset
) const
398 // TODO(F1): Split up poly-polygon into polygons, or even
399 // line segments, when subsets are requested.
401 // polygon only contains a single action, fail if subset
402 // requests different range
403 if( rSubset
.mnSubsetBegin
!= 0 ||
404 rSubset
.mnSubsetEnd
!= 1 )
407 return CachedPrimitiveBase::render( rTransformation
);
410 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
412 rendering::RenderState
aLocalState( maState
);
413 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
415 return tools::calcDevicePixelBounds(
417 mpCanvas
->getViewState(),
421 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
422 const Subset
& rSubset
) const
424 // TODO(F1): Split up poly-polygon into polygons, or even
425 // line segments, when subsets are requested.
427 // polygon only contains a single action, empty bounds
428 // if subset requests different range
429 if( rSubset
.mnSubsetBegin
!= 0 ||
430 rSubset
.mnSubsetEnd
!= 1 )
431 return ::basegfx::B2DRange();
433 return getBounds( rTransformation
);
436 sal_Int32
StrokedPolyPolyAction::getActionCount() const
438 // TODO(F1): Split up poly-polygon into polygons, or even
439 // line segments, when subsets are requested.
444 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
445 const CanvasSharedPtr
& rCanvas
,
446 const OutDevState
& rState
)
448 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
449 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
450 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
451 rState
.isFillColorSet
,
452 rState
.isLineColorSet
);
455 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
456 const CanvasSharedPtr
& rCanvas
,
457 const OutDevState
& rState
,
458 const rendering::Texture
& rTexture
)
460 return std::make_shared
<TexturedPolyPolyAction
>( rPoly
, rCanvas
, rState
, rTexture
);
463 std::shared_ptr
<Action
> PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
464 const CanvasSharedPtr
& rCanvas
,
465 const OutDevState
& rState
)
467 OSL_ENSURE( rState
.isLineColorSet
,
468 "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" );
470 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
472 rState
.isLineColorSet
);
475 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
476 const CanvasSharedPtr
& rCanvas
,
477 const OutDevState
& rState
,
478 const rendering::StrokeAttributes
& rStrokeAttributes
)
480 OSL_ENSURE( rState
.isLineColorSet
,
481 "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" );
482 return std::make_shared
<StrokedPolyPolyAction
>( rPoly
, rCanvas
, rState
, rStrokeAttributes
);
485 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
486 const CanvasSharedPtr
& rCanvas
,
487 const OutDevState
& rState
,
490 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
491 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
492 return std::make_shared
<PolyPolyAction
>( rPoly
, rCanvas
, rState
,
493 rState
.isFillColorSet
,
494 rState
.isLineColorSet
,
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */