Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <com/sun/star/rendering/XCanvas.hpp>
22 : #include <com/sun/star/rendering/TexturingMode.hpp>
23 :
24 : #include <sal/types.h>
25 : #include <vcl/canvastools.hxx>
26 :
27 : #include <basegfx/range/b2drectangle.hxx>
28 : #include <basegfx/tools/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 :
34 : #include <boost/utility.hpp>
35 :
36 : #include "cachedprimitivebase.hxx"
37 : #include "polypolyaction.hxx"
38 : #include "outdevstate.hxx"
39 : #include "mtftools.hxx"
40 :
41 :
42 : using namespace ::com::sun::star;
43 :
44 : namespace cppcanvas
45 : {
46 : namespace internal
47 : {
48 : namespace
49 : {
50 12 : class PolyPolyAction : public CachedPrimitiveBase
51 : {
52 : public:
53 : PolyPolyAction( const ::basegfx::B2DPolyPolygon&,
54 : const CanvasSharedPtr&,
55 : const OutDevState&,
56 : bool bFill,
57 : bool bStroke );
58 : PolyPolyAction( const ::basegfx::B2DPolyPolygon&,
59 : const CanvasSharedPtr&,
60 : const OutDevState&,
61 : bool bFill,
62 : bool bStroke,
63 : int nTransparency );
64 :
65 : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
66 : const Subset& rSubset ) const SAL_OVERRIDE;
67 :
68 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
69 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
70 : const Subset& rSubset ) const SAL_OVERRIDE;
71 :
72 : virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
73 :
74 : private:
75 : using Action::render;
76 : virtual bool renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
77 : const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
78 :
79 : const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly;
80 : const ::basegfx::B2DRange maBounds;
81 : const CanvasSharedPtr mpCanvas;
82 :
83 : // stroke color is now implicit: the maState.DeviceColor member
84 : rendering::RenderState maState;
85 :
86 : uno::Sequence< double > maFillColor;
87 : };
88 :
89 6 : PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly,
90 : const CanvasSharedPtr& rCanvas,
91 : const OutDevState& rState,
92 : bool bFill,
93 : bool bStroke ) :
94 : CachedPrimitiveBase( rCanvas, false ),
95 12 : mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ),
96 : maBounds( ::basegfx::tools::getRange(rPolyPoly) ),
97 : mpCanvas( rCanvas ),
98 : maState(),
99 18 : maFillColor()
100 : {
101 6 : tools::initRenderState(maState,rState);
102 :
103 6 : if( bFill )
104 6 : maFillColor = rState.fillColor;
105 :
106 6 : if( bStroke )
107 0 : maState.DeviceColor = rState.lineColor;
108 6 : }
109 :
110 0 : PolyPolyAction::PolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly,
111 : const CanvasSharedPtr& rCanvas,
112 : const OutDevState& rState,
113 : bool bFill,
114 : bool bStroke,
115 : int nTransparency ) :
116 : CachedPrimitiveBase( rCanvas, false ),
117 0 : mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ),
118 : maBounds( ::basegfx::tools::getRange(rPolyPoly) ),
119 : mpCanvas( rCanvas ),
120 : maState(),
121 0 : maFillColor()
122 : {
123 0 : tools::initRenderState(maState,rState);
124 :
125 0 : if( bFill )
126 : {
127 0 : maFillColor = rState.fillColor;
128 :
129 0 : if( maFillColor.getLength() < 4 )
130 0 : maFillColor.realloc( 4 );
131 :
132 : // TODO(F1): Color management
133 : // adapt fill color transparency
134 0 : maFillColor[3] = 1.0 - nTransparency / 100.0;
135 : }
136 :
137 0 : if( bStroke )
138 : {
139 0 : maState.DeviceColor = rState.lineColor;
140 :
141 0 : if( maState.DeviceColor.getLength() < 4 )
142 0 : maState.DeviceColor.realloc( 4 );
143 :
144 : // TODO(F1): Color management
145 : // adapt fill color transparency
146 0 : maState.DeviceColor[3] = 1.0 - nTransparency / 100.0;
147 : }
148 0 : }
149 :
150 6 : bool PolyPolyAction::renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
151 : const ::basegfx::B2DHomMatrix& rTransformation ) const
152 : {
153 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
154 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex << this );
155 :
156 6 : rendering::RenderState aLocalState( maState );
157 6 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
158 :
159 6 : if( maFillColor.getLength() )
160 : {
161 : // TODO(E3): Use DBO's finalizer here,
162 : // fillPolyPolygon() might throw
163 6 : const uno::Sequence< double > aTmpColor( aLocalState.DeviceColor );
164 6 : aLocalState.DeviceColor = maFillColor;
165 :
166 18 : rCachedPrimitive = mpCanvas->getUNOCanvas()->fillPolyPolygon( mxPolyPoly,
167 6 : mpCanvas->getViewState(),
168 12 : aLocalState );
169 :
170 6 : aLocalState.DeviceColor = aTmpColor;
171 : }
172 :
173 6 : if( aLocalState.DeviceColor.getLength() )
174 : {
175 0 : rCachedPrimitive = mpCanvas->getUNOCanvas()->drawPolyPolygon( mxPolyPoly,
176 0 : mpCanvas->getViewState(),
177 0 : aLocalState );
178 : }
179 :
180 6 : return true;
181 : }
182 :
183 0 : bool PolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
184 : const Subset& rSubset ) const
185 : {
186 : // TODO(F1): Split up poly-polygon into polygons, or even
187 : // line segments, when subsets are requested.
188 :
189 : // polygon only contains a single action, fail if subset
190 : // requests different range
191 0 : if( rSubset.mnSubsetBegin != 0 ||
192 0 : rSubset.mnSubsetEnd != 1 )
193 0 : return false;
194 :
195 0 : return CachedPrimitiveBase::render( rTransformation );
196 : }
197 :
198 0 : ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
199 : {
200 0 : rendering::RenderState aLocalState( maState );
201 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
202 :
203 : return tools::calcDevicePixelBounds(
204 : maBounds,
205 0 : mpCanvas->getViewState(),
206 0 : aLocalState );
207 : }
208 :
209 0 : ::basegfx::B2DRange PolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
210 : const Subset& rSubset ) const
211 : {
212 : // TODO(F1): Split up poly-polygon into polygons, or even
213 : // line segments, when subsets are requested.
214 :
215 : // polygon only contains a single action, empty bounds
216 : // if subset requests different range
217 0 : if( rSubset.mnSubsetBegin != 0 ||
218 0 : rSubset.mnSubsetEnd != 1 )
219 0 : return ::basegfx::B2DRange();
220 :
221 0 : return getBounds( rTransformation );
222 : }
223 :
224 6 : sal_Int32 PolyPolyAction::getActionCount() const
225 : {
226 : // TODO(F1): Split up poly-polygon into polygons, or even
227 : // line segments, when subsets are requested.
228 6 : return 1;
229 : }
230 :
231 :
232 :
233 :
234 0 : class TexturedPolyPolyAction : public CachedPrimitiveBase
235 : {
236 : public:
237 : TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
238 : const CanvasSharedPtr& rCanvas,
239 : const OutDevState& rState,
240 : const rendering::Texture& rTexture );
241 :
242 : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
243 : const Subset& rSubset ) const SAL_OVERRIDE;
244 :
245 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
246 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
247 : const Subset& rSubset ) const SAL_OVERRIDE;
248 :
249 : virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
250 :
251 : private:
252 : using Action::render;
253 : virtual bool renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
254 : const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
255 :
256 : const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly;
257 : const ::basegfx::B2DRectangle maBounds;
258 : const CanvasSharedPtr mpCanvas;
259 :
260 : // stroke color is now implicit: the maState.DeviceColor member
261 : rendering::RenderState maState;
262 : const rendering::Texture maTexture;
263 : };
264 :
265 0 : TexturedPolyPolyAction::TexturedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly,
266 : const CanvasSharedPtr& rCanvas,
267 : const OutDevState& rState,
268 : const rendering::Texture& rTexture ) :
269 : CachedPrimitiveBase( rCanvas, true ),
270 0 : mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ),
271 : maBounds( ::basegfx::tools::getRange(rPolyPoly) ),
272 : mpCanvas( rCanvas ),
273 : maState(),
274 0 : maTexture( rTexture )
275 : {
276 0 : tools::initRenderState(maState,rState);
277 0 : }
278 :
279 0 : bool TexturedPolyPolyAction::renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
280 : const ::basegfx::B2DHomMatrix& rTransformation ) const
281 : {
282 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
283 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex << this );
284 :
285 0 : rendering::RenderState aLocalState( maState );
286 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
287 :
288 0 : uno::Sequence< rendering::Texture > aSeq(1);
289 0 : aSeq[0] = maTexture;
290 :
291 0 : rCachedPrimitive = mpCanvas->getUNOCanvas()->fillTexturedPolyPolygon( mxPolyPoly,
292 0 : mpCanvas->getViewState(),
293 : aLocalState,
294 0 : aSeq );
295 0 : return true;
296 : }
297 :
298 0 : bool TexturedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
299 : const Subset& rSubset ) const
300 : {
301 : // TODO(F1): Split up poly-polygon into polygons, or even
302 : // line segments, when subsets are requested.
303 :
304 : // polygon only contains a single action, fail if subset
305 : // requests different range
306 0 : if( rSubset.mnSubsetBegin != 0 ||
307 0 : rSubset.mnSubsetEnd != 1 )
308 0 : return false;
309 :
310 0 : return CachedPrimitiveBase::render( rTransformation );
311 : }
312 :
313 0 : ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
314 : {
315 0 : rendering::RenderState aLocalState( maState );
316 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
317 :
318 : return tools::calcDevicePixelBounds(
319 : maBounds,
320 0 : mpCanvas->getViewState(),
321 0 : aLocalState );
322 : }
323 :
324 0 : ::basegfx::B2DRange TexturedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
325 : const Subset& rSubset ) const
326 : {
327 : // TODO(F1): Split up poly-polygon into polygons, or even
328 : // line segments, when subsets are requested.
329 :
330 : // polygon only contains a single action, empty bounds
331 : // if subset requests different range
332 0 : if( rSubset.mnSubsetBegin != 0 ||
333 0 : rSubset.mnSubsetEnd != 1 )
334 0 : return ::basegfx::B2DRange();
335 :
336 0 : return getBounds( rTransformation );
337 : }
338 :
339 0 : sal_Int32 TexturedPolyPolyAction::getActionCount() const
340 : {
341 : // TODO(F1): Split up poly-polygon into polygons, or even
342 : // line segments, when subsets are requested.
343 0 : return 1;
344 : }
345 :
346 :
347 :
348 8 : class StrokedPolyPolyAction : public CachedPrimitiveBase
349 : {
350 : public:
351 : StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
352 : const CanvasSharedPtr& rCanvas,
353 : const OutDevState& rState,
354 : const rendering::StrokeAttributes& rStrokeAttributes );
355 :
356 : virtual bool renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
357 : const Subset& rSubset ) const SAL_OVERRIDE;
358 :
359 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
360 : virtual ::basegfx::B2DRange getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
361 : const Subset& rSubset ) const SAL_OVERRIDE;
362 :
363 : virtual sal_Int32 getActionCount() const SAL_OVERRIDE;
364 :
365 : private:
366 : using Action::render;
367 : virtual bool renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
368 : const ::basegfx::B2DHomMatrix& rTransformation ) const SAL_OVERRIDE;
369 :
370 : const uno::Reference< rendering::XPolyPolygon2D > mxPolyPoly;
371 : const ::basegfx::B2DRectangle maBounds;
372 : const CanvasSharedPtr mpCanvas;
373 : rendering::RenderState maState;
374 : const rendering::StrokeAttributes maStrokeAttributes;
375 : };
376 :
377 4 : StrokedPolyPolyAction::StrokedPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPolyPoly,
378 : const CanvasSharedPtr& rCanvas,
379 : const OutDevState& rState,
380 : const rendering::StrokeAttributes& rStrokeAttributes ) :
381 : CachedPrimitiveBase( rCanvas, false ),
382 8 : mxPolyPoly( ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon( rCanvas->getUNOCanvas()->getDevice(), rPolyPoly) ),
383 : maBounds( ::basegfx::tools::getRange(rPolyPoly) ),
384 : mpCanvas( rCanvas ),
385 : maState(),
386 12 : maStrokeAttributes( rStrokeAttributes )
387 : {
388 4 : tools::initRenderState(maState,rState);
389 4 : maState.DeviceColor = rState.lineColor;
390 4 : }
391 :
392 4 : bool StrokedPolyPolyAction::renderPrimitive( uno::Reference< rendering::XCachedPrimitive >& rCachedPrimitive,
393 : const ::basegfx::B2DHomMatrix& rTransformation ) const
394 : {
395 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction::renderPrimitive()" );
396 : SAL_INFO( "cppcanvas.emf", "::cppcanvas::internal::PolyPolyAction: 0x" << std::hex << this );
397 :
398 4 : rendering::RenderState aLocalState( maState );
399 4 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
400 :
401 16 : rCachedPrimitive = mpCanvas->getUNOCanvas()->strokePolyPolygon( mxPolyPoly,
402 4 : mpCanvas->getViewState(),
403 : aLocalState,
404 8 : maStrokeAttributes );
405 4 : return true;
406 : }
407 :
408 0 : bool StrokedPolyPolyAction::renderSubset( const ::basegfx::B2DHomMatrix& rTransformation,
409 : const Subset& rSubset ) const
410 : {
411 : // TODO(F1): Split up poly-polygon into polygons, or even
412 : // line segments, when subsets are requested.
413 :
414 : // polygon only contains a single action, fail if subset
415 : // requests different range
416 0 : if( rSubset.mnSubsetBegin != 0 ||
417 0 : rSubset.mnSubsetEnd != 1 )
418 0 : return false;
419 :
420 0 : return CachedPrimitiveBase::render( rTransformation );
421 : }
422 :
423 0 : ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation ) const
424 : {
425 0 : rendering::RenderState aLocalState( maState );
426 0 : ::canvas::tools::prependToRenderState(aLocalState, rTransformation);
427 :
428 : return tools::calcDevicePixelBounds(
429 : maBounds,
430 0 : mpCanvas->getViewState(),
431 0 : aLocalState );
432 : }
433 :
434 0 : ::basegfx::B2DRange StrokedPolyPolyAction::getBounds( const ::basegfx::B2DHomMatrix& rTransformation,
435 : const Subset& rSubset ) const
436 : {
437 : // TODO(F1): Split up poly-polygon into polygons, or even
438 : // line segments, when subsets are requested.
439 :
440 : // polygon only contains a single action, empty bounds
441 : // if subset requests different range
442 0 : if( rSubset.mnSubsetBegin != 0 ||
443 0 : rSubset.mnSubsetEnd != 1 )
444 0 : return ::basegfx::B2DRange();
445 :
446 0 : return getBounds( rTransformation );
447 : }
448 :
449 4 : sal_Int32 StrokedPolyPolyAction::getActionCount() const
450 : {
451 : // TODO(F1): Split up poly-polygon into polygons, or even
452 : // line segments, when subsets are requested.
453 4 : return 1;
454 : }
455 : }
456 :
457 6 : ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
458 : const CanvasSharedPtr& rCanvas,
459 : const OutDevState& rState )
460 : {
461 : OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet,
462 : "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
463 : return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState,
464 : rState.isFillColorSet,
465 6 : rState.isLineColorSet ) );
466 : }
467 :
468 0 : ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
469 : const CanvasSharedPtr& rCanvas,
470 : const OutDevState& rState,
471 : const rendering::Texture& rTexture )
472 : {
473 0 : return ActionSharedPtr( new TexturedPolyPolyAction( rPoly, rCanvas, rState, rTexture ) );
474 : }
475 :
476 0 : ActionSharedPtr PolyPolyActionFactory::createLinePolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
477 : const CanvasSharedPtr& rCanvas,
478 : const OutDevState& rState )
479 : {
480 : OSL_ENSURE( rState.isLineColorSet,
481 : "PolyPolyActionFactory::createLinePolyPolyAction() called with empty line color" );
482 :
483 : return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState,
484 : false,
485 0 : rState.isLineColorSet ) );
486 : }
487 :
488 4 : ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
489 : const CanvasSharedPtr& rCanvas,
490 : const OutDevState& rState,
491 : const rendering::StrokeAttributes& rStrokeAttributes )
492 : {
493 : OSL_ENSURE( rState.isLineColorSet,
494 : "PolyPolyActionFactory::createPolyPolyAction() for strokes called with empty line color" );
495 4 : return ActionSharedPtr( new StrokedPolyPolyAction( rPoly, rCanvas, rState, rStrokeAttributes ) );
496 : }
497 :
498 0 : ActionSharedPtr PolyPolyActionFactory::createPolyPolyAction( const ::basegfx::B2DPolyPolygon& rPoly,
499 : const CanvasSharedPtr& rCanvas,
500 : const OutDevState& rState,
501 : int nTransparency )
502 : {
503 : OSL_ENSURE( rState.isLineColorSet || rState.isFillColorSet,
504 : "PolyPolyActionFactory::createPolyPolyAction() with empty line and fill color" );
505 : return ActionSharedPtr( new PolyPolyAction( rPoly, rCanvas, rState,
506 : rState.isFillColorSet,
507 : rState.isLineColorSet,
508 0 : nTransparency ) );
509 : }
510 :
511 : }
512 : }
513 :
514 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|