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