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>
22 #include <com/sun/star/rendering/TexturingMode.hpp>
24 #include <sal/types.h>
25 #include <vcl/canvastools.hxx>
27 #include <basegfx/range/b2drectangle.hxx>
28 #include <basegfx/utils/canvastools.hxx>
29 #include <basegfx/polygon/b2dpolypolygon.hxx>
30 #include <basegfx/polygon/b2dpolypolygontools.hxx>
31 #include <basegfx/matrix/b2dhommatrix.hxx>
32 #include <canvas/canvastools.hxx>
33 #include <sal/log.hxx>
35 #include "cachedprimitivebase.hxx"
36 #include "polypolyaction.hxx"
37 #include <outdevstate.hxx>
38 #include "mtftools.hxx"
41 using namespace ::com::sun::star
;
49 class PolyPolyAction
: public CachedPrimitiveBase
52 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
53 const CanvasSharedPtr
&,
57 PolyPolyAction( const ::basegfx::B2DPolyPolygon
&,
58 const CanvasSharedPtr
&,
64 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
65 const Subset
& rSubset
) const override
;
67 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
68 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
69 const Subset
& rSubset
) const override
;
71 virtual sal_Int32
getActionCount() const override
;
75 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
76 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
78 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
79 const ::basegfx::B2DRange maBounds
;
80 const CanvasSharedPtr mpCanvas
;
82 // stroke color is now implicit: the maState.DeviceColor member
83 rendering::RenderState maState
;
85 uno::Sequence
< double > maFillColor
;
88 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
89 const CanvasSharedPtr
& rCanvas
,
90 const OutDevState
& rState
,
93 CachedPrimitiveBase( rCanvas
, false ),
94 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
95 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
100 tools::initRenderState(maState
,rState
);
103 maFillColor
= rState
.fillColor
;
106 maState
.DeviceColor
= rState
.lineColor
;
109 PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
110 const CanvasSharedPtr
& rCanvas
,
111 const OutDevState
& rState
,
114 int nTransparency
) :
115 CachedPrimitiveBase( rCanvas
, false ),
116 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
117 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
122 tools::initRenderState(maState
,rState
);
126 maFillColor
= rState
.fillColor
;
128 if( maFillColor
.getLength() < 4 )
129 maFillColor
.realloc( 4 );
131 // TODO(F1): Color management
132 // adapt fill color transparency
133 maFillColor
[3] = 1.0 - nTransparency
/ 100.0;
138 maState
.DeviceColor
= rState
.lineColor
;
140 if( maState
.DeviceColor
.getLength() < 4 )
141 maState
.DeviceColor
.realloc( 4 );
143 // TODO(F1): Color management
144 // adapt fill color transparency
145 maState
.DeviceColor
[3] = 1.0 - nTransparency
/ 100.0;
149 bool PolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
150 const ::basegfx::B2DHomMatrix
& rTransformation
) const
152 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
153 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
155 rendering::RenderState
aLocalState( maState
);
156 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
158 if( maFillColor
.getLength() )
160 // TODO(E3): Use DBO's finalizer here,
161 // fillPolyPolygon() might throw
162 const uno::Sequence
< double > aTmpColor( aLocalState
.DeviceColor
);
163 aLocalState
.DeviceColor
= maFillColor
;
165 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillPolyPolygon( mxPolyPoly
,
166 mpCanvas
->getViewState(),
169 aLocalState
.DeviceColor
= aTmpColor
;
172 if( aLocalState
.DeviceColor
.getLength() )
174 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->drawPolyPolygon( mxPolyPoly
,
175 mpCanvas
->getViewState(),
182 bool PolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
183 const Subset
& rSubset
) const
185 // TODO(F1): Split up poly-polygon into polygons, or even
186 // line segments, when subsets are requested.
188 // polygon only contains a single action, fail if subset
189 // requests different range
190 if( rSubset
.mnSubsetBegin
!= 0 ||
191 rSubset
.mnSubsetEnd
!= 1 )
194 return CachedPrimitiveBase::render( rTransformation
);
197 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
199 rendering::RenderState
aLocalState( maState
);
200 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
202 return tools::calcDevicePixelBounds(
204 mpCanvas
->getViewState(),
208 ::basegfx::B2DRange
PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
209 const Subset
& rSubset
) const
211 // TODO(F1): Split up poly-polygon into polygons, or even
212 // line segments, when subsets are requested.
214 // polygon only contains a single action, empty bounds
215 // if subset requests different range
216 if( rSubset
.mnSubsetBegin
!= 0 ||
217 rSubset
.mnSubsetEnd
!= 1 )
218 return ::basegfx::B2DRange();
220 return getBounds( rTransformation
);
223 sal_Int32
PolyPolyAction::getActionCount() const
225 // TODO(F1): Split up poly-polygon into polygons, or even
226 // line segments, when subsets are requested.
231 class TexturedPolyPolyAction
: public CachedPrimitiveBase
234 TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
235 const CanvasSharedPtr
& rCanvas
,
236 const OutDevState
& rState
,
237 const rendering::Texture
& rTexture
);
239 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
240 const Subset
& rSubset
) const override
;
242 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
243 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
244 const Subset
& rSubset
) const override
;
246 virtual sal_Int32
getActionCount() const override
;
249 using Action::render
;
250 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
251 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
253 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
254 const ::basegfx::B2DRectangle maBounds
;
255 const CanvasSharedPtr mpCanvas
;
257 // stroke color is now implicit: the maState.DeviceColor member
258 rendering::RenderState maState
;
259 const rendering::Texture maTexture
;
262 TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
263 const CanvasSharedPtr
& rCanvas
,
264 const OutDevState
& rState
,
265 const rendering::Texture
& rTexture
) :
266 CachedPrimitiveBase( rCanvas
, true ),
267 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
268 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
271 maTexture( rTexture
)
273 tools::initRenderState(maState
,rState
);
276 bool TexturedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
277 const ::basegfx::B2DHomMatrix
& rTransformation
) const
279 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
280 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
282 rendering::RenderState
aLocalState( maState
);
283 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
285 uno::Sequence
< rendering::Texture
> aSeq(1);
288 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly
,
289 mpCanvas
->getViewState(),
295 bool TexturedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
296 const Subset
& rSubset
) const
298 // TODO(F1): Split up poly-polygon into polygons, or even
299 // line segments, when subsets are requested.
301 // polygon only contains a single action, fail if subset
302 // requests different range
303 if( rSubset
.mnSubsetBegin
!= 0 ||
304 rSubset
.mnSubsetEnd
!= 1 )
307 return CachedPrimitiveBase::render( rTransformation
);
310 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
312 rendering::RenderState
aLocalState( maState
);
313 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
315 return tools::calcDevicePixelBounds(
317 mpCanvas
->getViewState(),
321 ::basegfx::B2DRange
TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
322 const Subset
& rSubset
) const
324 // TODO(F1): Split up poly-polygon into polygons, or even
325 // line segments, when subsets are requested.
327 // polygon only contains a single action, empty bounds
328 // if subset requests different range
329 if( rSubset
.mnSubsetBegin
!= 0 ||
330 rSubset
.mnSubsetEnd
!= 1 )
331 return ::basegfx::B2DRange();
333 return getBounds( rTransformation
);
336 sal_Int32
TexturedPolyPolyAction::getActionCount() const
338 // TODO(F1): Split up poly-polygon into polygons, or even
339 // line segments, when subsets are requested.
344 class StrokedPolyPolyAction
: public CachedPrimitiveBase
347 StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
348 const CanvasSharedPtr
& rCanvas
,
349 const OutDevState
& rState
,
350 const rendering::StrokeAttributes
& rStrokeAttributes
);
352 virtual bool renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
353 const Subset
& rSubset
) const override
;
355 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
356 virtual ::basegfx::B2DRange
getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
357 const Subset
& rSubset
) const override
;
359 virtual sal_Int32
getActionCount() const override
;
362 using Action::render
;
363 virtual bool renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
364 const ::basegfx::B2DHomMatrix
& rTransformation
) const override
;
366 const uno::Reference
< rendering::XPolyPolygon2D
> mxPolyPoly
;
367 const ::basegfx::B2DRectangle maBounds
;
368 const CanvasSharedPtr mpCanvas
;
369 rendering::RenderState maState
;
370 const rendering::StrokeAttributes maStrokeAttributes
;
373 StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPolyPoly
,
374 const CanvasSharedPtr
& rCanvas
,
375 const OutDevState
& rState
,
376 const rendering::StrokeAttributes
& rStrokeAttributes
) :
377 CachedPrimitiveBase( rCanvas
, false ),
378 mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas
->getUNOCanvas()->getDevice(), rPolyPoly
) ),
379 maBounds( ::basegfx::utils::getRange(rPolyPoly
) ),
382 maStrokeAttributes( rStrokeAttributes
)
384 tools::initRenderState(maState
,rState
);
385 maState
.DeviceColor
= rState
.lineColor
;
388 bool StrokedPolyPolyAction::renderPrimitive( uno::Reference
< rendering::XCachedPrimitive
>& rCachedPrimitive
,
389 const ::basegfx::B2DHomMatrix
& rTransformation
) const
391 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
392 SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex
<< this );
394 rendering::RenderState
aLocalState( maState
);
395 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
397 rCachedPrimitive
= mpCanvas
->getUNOCanvas()->strokePolyPolygon( mxPolyPoly
,
398 mpCanvas
->getViewState(),
400 maStrokeAttributes
);
404 bool StrokedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix
& rTransformation
,
405 const Subset
& rSubset
) const
407 // TODO(F1): Split up poly-polygon into polygons, or even
408 // line segments, when subsets are requested.
410 // polygon only contains a single action, fail if subset
411 // requests different range
412 if( rSubset
.mnSubsetBegin
!= 0 ||
413 rSubset
.mnSubsetEnd
!= 1 )
416 return CachedPrimitiveBase::render( rTransformation
);
419 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
) const
421 rendering::RenderState
aLocalState( maState
);
422 ::canvas::tools::prependToRenderState(aLocalState
, rTransformation
);
424 return tools::calcDevicePixelBounds(
426 mpCanvas
->getViewState(),
430 ::basegfx::B2DRange
StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix
& rTransformation
,
431 const Subset
& rSubset
) const
433 // TODO(F1): Split up poly-polygon into polygons, or even
434 // line segments, when subsets are requested.
436 // polygon only contains a single action, empty bounds
437 // if subset requests different range
438 if( rSubset
.mnSubsetBegin
!= 0 ||
439 rSubset
.mnSubsetEnd
!= 1 )
440 return ::basegfx::B2DRange();
442 return getBounds( rTransformation
);
445 sal_Int32
StrokedPolyPolyAction::getActionCount() const
447 // TODO(F1): Split up poly-polygon into polygons, or even
448 // line segments, when subsets are requested.
453 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
454 const CanvasSharedPtr
& rCanvas
,
455 const OutDevState
& rState
)
457 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
458 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
459 return std::shared_ptr
<Action
>( new PolyPolyAction( rPoly
, rCanvas
, rState
,
460 rState
.isFillColorSet
,
461 rState
.isLineColorSet
) );
464 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
465 const CanvasSharedPtr
& rCanvas
,
466 const OutDevState
& rState
,
467 const rendering::Texture
& rTexture
)
469 return std::shared_ptr
<Action
>( new TexturedPolyPolyAction( rPoly
, rCanvas
, rState
, rTexture
) );
472 std::shared_ptr
<Action
> PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
473 const CanvasSharedPtr
& rCanvas
,
474 const OutDevState
& rState
)
476 OSL_ENSURE( rState
.isLineColorSet
,
477 "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" );
479 return std::shared_ptr
<Action
>( new PolyPolyAction( rPoly
, rCanvas
, rState
,
481 rState
.isLineColorSet
) );
484 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
485 const CanvasSharedPtr
& rCanvas
,
486 const OutDevState
& rState
,
487 const rendering::StrokeAttributes
& rStrokeAttributes
)
489 OSL_ENSURE( rState
.isLineColorSet
,
490 "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" );
491 return std::shared_ptr
<Action
>( new StrokedPolyPolyAction( rPoly
, rCanvas
, rState
, rStrokeAttributes
) );
494 std::shared_ptr
<Action
> PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon
& rPoly
,
495 const CanvasSharedPtr
& rCanvas
,
496 const OutDevState
& rState
,
499 OSL_ENSURE( rState
.isLineColorSet
|| rState
.isFillColorSet
,
500 "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
501 return std::shared_ptr
<Action
>( new PolyPolyAction( rPoly
, rCanvas
, rState
,
502 rState
.isFillColorSet
,
503 rState
.isLineColorSet
,
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */