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