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_canvas.hxx" 30 31 #include <canvas/debug.hxx> 32 #include <tools/diagnose_ex.h> 33 34 #include <com/sun/star/geometry/AffineMatrix2D.hpp> 35 #include <com/sun/star/geometry/Matrix2D.hpp> 36 #include <com/sun/star/awt/Rectangle.hpp> 37 #include <com/sun/star/util/Endianness.hpp> 38 #include <com/sun/star/rendering/XIntegerBitmapColorSpace.hpp> 39 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp> 40 #include <com/sun/star/rendering/ColorSpaceType.hpp> 41 #include <com/sun/star/rendering/ColorComponentTag.hpp> 42 #include <com/sun/star/rendering/RenderingIntent.hpp> 43 #include <com/sun/star/rendering/RenderState.hpp> 44 #include <com/sun/star/rendering/ViewState.hpp> 45 #include <com/sun/star/rendering/XCanvas.hpp> 46 #include <com/sun/star/rendering/XColorSpace.hpp> 47 #include <com/sun/star/rendering/CompositeOperation.hpp> 48 #include <com/sun/star/beans/XPropertySet.hpp> 49 #include <com/sun/star/lang/XServiceInfo.hpp> 50 51 #include <basegfx/matrix/b2dhommatrix.hxx> 52 #include <basegfx/range/b2drange.hxx> 53 #include <basegfx/range/b2irange.hxx> 54 #include <basegfx/range/b2drectangle.hxx> 55 #include <basegfx/point/b2dpoint.hxx> 56 #include <basegfx/point/b2ipoint.hxx> 57 #include <basegfx/vector/b2ivector.hxx> 58 #include <basegfx/polygon/b2dpolygon.hxx> 59 #include <basegfx/polygon/b2dpolygontools.hxx> 60 #include <basegfx/polygon/b2dpolypolygontools.hxx> 61 #include <basegfx/tools/canvastools.hxx> 62 #include <basegfx/numeric/ftools.hxx> 63 #include <basegfx/matrix/b2dhommatrixtools.hxx> 64 65 #include <cppuhelper/compbase1.hxx> 66 #include <rtl/instance.hxx> 67 #include <toolkit/helper/vclunohelper.hxx> 68 #include <vcl/window.hxx> 69 #include <vcl/canvastools.hxx> 70 71 #include <canvas/canvastools.hxx> 72 73 #include <limits> 74 75 76 using namespace ::com::sun::star; 77 78 namespace com { namespace sun { namespace star { namespace rendering 79 { 80 bool operator==( const RenderState& renderState1, 81 const RenderState& renderState2 ) 82 { 83 if( renderState1.Clip != renderState2.Clip ) 84 return false; 85 86 if( renderState1.DeviceColor != renderState2.DeviceColor ) 87 return false; 88 89 if( renderState1.CompositeOperation != renderState2.CompositeOperation ) 90 return false; 91 92 ::basegfx::B2DHomMatrix mat1, mat2; 93 ::canvas::tools::getRenderStateTransform( mat1, renderState1 ); 94 ::canvas::tools::getRenderStateTransform( mat2, renderState2 ); 95 if( mat1 != mat2 ) 96 return false; 97 98 return true; 99 } 100 101 bool operator==( const ViewState& viewState1, 102 const ViewState& viewState2 ) 103 { 104 if( viewState1.Clip != viewState2.Clip ) 105 return false; 106 107 ::basegfx::B2DHomMatrix mat1, mat2; 108 ::canvas::tools::getViewStateTransform( mat1, viewState1 ); 109 ::canvas::tools::getViewStateTransform( mat2, viewState2 ); 110 if( mat1 != mat2 ) 111 return false; 112 113 return true; 114 } 115 }}}} 116 117 namespace canvas 118 { 119 namespace tools 120 { 121 geometry::RealSize2D createInfiniteSize2D() 122 { 123 return geometry::RealSize2D( 124 ::std::numeric_limits<double>::infinity(), 125 ::std::numeric_limits<double>::infinity() ); 126 } 127 128 rendering::RenderState& initRenderState( rendering::RenderState& renderState ) 129 { 130 // setup identity transform 131 setIdentityAffineMatrix2D( renderState.AffineTransform ); 132 renderState.Clip = uno::Reference< rendering::XPolyPolygon2D >(); 133 renderState.DeviceColor = uno::Sequence< double >(); 134 renderState.CompositeOperation = rendering::CompositeOperation::OVER; 135 136 return renderState; 137 } 138 139 rendering::ViewState& initViewState( rendering::ViewState& viewState ) 140 { 141 // setup identity transform 142 setIdentityAffineMatrix2D( viewState.AffineTransform ); 143 viewState.Clip = uno::Reference< rendering::XPolyPolygon2D >(); 144 145 return viewState; 146 } 147 148 ::basegfx::B2DHomMatrix& getViewStateTransform( ::basegfx::B2DHomMatrix& transform, 149 const rendering::ViewState& viewState ) 150 { 151 return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, viewState.AffineTransform ); 152 } 153 154 rendering::ViewState& setViewStateTransform( rendering::ViewState& viewState, 155 const ::basegfx::B2DHomMatrix& transform ) 156 { 157 ::basegfx::unotools::affineMatrixFromHomMatrix( viewState.AffineTransform, transform ); 158 159 return viewState; 160 } 161 162 ::basegfx::B2DHomMatrix& getRenderStateTransform( ::basegfx::B2DHomMatrix& transform, 163 const rendering::RenderState& renderState ) 164 { 165 return ::basegfx::unotools::homMatrixFromAffineMatrix( transform, renderState.AffineTransform ); 166 } 167 168 rendering::RenderState& setRenderStateTransform( rendering::RenderState& renderState, 169 const ::basegfx::B2DHomMatrix& transform ) 170 { 171 ::basegfx::unotools::affineMatrixFromHomMatrix( renderState.AffineTransform, transform ); 172 173 return renderState; 174 } 175 176 rendering::RenderState& appendToRenderState( rendering::RenderState& renderState, 177 const ::basegfx::B2DHomMatrix& rTransform ) 178 { 179 ::basegfx::B2DHomMatrix transform; 180 181 getRenderStateTransform( transform, renderState ); 182 return setRenderStateTransform( renderState, transform * rTransform ); 183 } 184 185 rendering::ViewState& appendToViewState( rendering::ViewState& viewState, 186 const ::basegfx::B2DHomMatrix& rTransform ) 187 { 188 ::basegfx::B2DHomMatrix transform; 189 190 getViewStateTransform( transform, viewState ); 191 return setViewStateTransform( viewState, transform * rTransform ); 192 } 193 194 rendering::RenderState& prependToRenderState( rendering::RenderState& renderState, 195 const ::basegfx::B2DHomMatrix& rTransform ) 196 { 197 ::basegfx::B2DHomMatrix transform; 198 199 getRenderStateTransform( transform, renderState ); 200 return setRenderStateTransform( renderState, rTransform * transform ); 201 } 202 203 rendering::ViewState& prependToViewState( rendering::ViewState& viewState, 204 const ::basegfx::B2DHomMatrix& rTransform ) 205 { 206 ::basegfx::B2DHomMatrix transform; 207 208 getViewStateTransform( transform, viewState ); 209 return setViewStateTransform( viewState, rTransform * transform ); 210 } 211 212 ::basegfx::B2DHomMatrix& mergeViewAndRenderTransform( ::basegfx::B2DHomMatrix& combinedTransform, 213 const rendering::ViewState& viewState, 214 const rendering::RenderState& renderState ) 215 { 216 ::basegfx::B2DHomMatrix viewTransform; 217 218 ::basegfx::unotools::homMatrixFromAffineMatrix( combinedTransform, renderState.AffineTransform ); 219 ::basegfx::unotools::homMatrixFromAffineMatrix( viewTransform, viewState.AffineTransform ); 220 221 // this statement performs combinedTransform = viewTransform * combinedTransform 222 combinedTransform *= viewTransform; 223 224 return combinedTransform; 225 } 226 227 rendering::ViewState& mergeViewAndRenderState( rendering::ViewState& resultViewState, 228 const rendering::ViewState& viewState, 229 const rendering::RenderState& renderState, 230 const uno::Reference< rendering::XCanvas >& /*xCanvas*/ ) 231 { 232 ::basegfx::B2DHomMatrix aTmpMatrix; 233 geometry::AffineMatrix2D convertedMatrix; 234 235 resultViewState.Clip = NULL; // TODO(F2): intersect clippings 236 237 return setViewStateTransform( 238 resultViewState, 239 mergeViewAndRenderTransform( aTmpMatrix, 240 viewState, 241 renderState ) ); 242 } 243 244 geometry::AffineMatrix2D& setIdentityAffineMatrix2D( geometry::AffineMatrix2D& matrix ) 245 { 246 matrix.m00 = 1.0; 247 matrix.m01 = 0.0; 248 matrix.m02 = 0.0; 249 matrix.m10 = 0.0; 250 matrix.m11 = 1.0; 251 matrix.m12 = 0.0; 252 253 return matrix; 254 } 255 256 geometry::Matrix2D& setIdentityMatrix2D( geometry::Matrix2D& matrix ) 257 { 258 matrix.m00 = 1.0; 259 matrix.m01 = 0.0; 260 matrix.m10 = 0.0; 261 matrix.m11 = 1.0; 262 263 return matrix; 264 } 265 266 namespace 267 { 268 class StandardColorSpace : public cppu::WeakImplHelper1< com::sun::star::rendering::XIntegerBitmapColorSpace > 269 { 270 private: 271 uno::Sequence< sal_Int8 > maComponentTags; 272 uno::Sequence< sal_Int32 > maBitCounts; 273 274 virtual ::sal_Int8 SAL_CALL getType( ) throw (uno::RuntimeException) 275 { 276 return rendering::ColorSpaceType::RGB; 277 } 278 virtual uno::Sequence< ::sal_Int8 > SAL_CALL getComponentTags( ) throw (uno::RuntimeException) 279 { 280 return maComponentTags; 281 } 282 virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) throw (uno::RuntimeException) 283 { 284 return rendering::RenderingIntent::PERCEPTUAL; 285 } 286 virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties( ) throw (uno::RuntimeException) 287 { 288 return uno::Sequence< beans::PropertyValue >(); 289 } 290 virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >& deviceColor, 291 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, 292 uno::RuntimeException) 293 { 294 // TODO(P3): if we know anything about target 295 // colorspace, this can be greatly sped up 296 uno::Sequence<rendering::ARGBColor> aIntermediate( 297 convertToARGB(deviceColor)); 298 return targetColorSpace->convertFromARGB(aIntermediate); 299 } 300 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 301 { 302 const double* pIn( deviceColor.getConstArray() ); 303 const sal_Size nLen( deviceColor.getLength() ); 304 ENSURE_ARG_OR_THROW2(nLen%4==0, 305 "number of channels no multiple of 4", 306 static_cast<rendering::XColorSpace*>(this), 0); 307 308 uno::Sequence< rendering::RGBColor > aRes(nLen/4); 309 rendering::RGBColor* pOut( aRes.getArray() ); 310 for( sal_Size i=0; i<nLen; i+=4 ) 311 { 312 *pOut++ = rendering::RGBColor(pIn[0],pIn[1],pIn[2]); 313 pIn += 4; 314 } 315 return aRes; 316 } 317 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 318 { 319 const double* pIn( deviceColor.getConstArray() ); 320 const sal_Size nLen( deviceColor.getLength() ); 321 ENSURE_ARG_OR_THROW2(nLen%4==0, 322 "number of channels no multiple of 4", 323 static_cast<rendering::XColorSpace*>(this), 0); 324 325 uno::Sequence< rendering::ARGBColor > aRes(nLen/4); 326 rendering::ARGBColor* pOut( aRes.getArray() ); 327 for( sal_Size i=0; i<nLen; i+=4 ) 328 { 329 *pOut++ = rendering::ARGBColor(pIn[3],pIn[0],pIn[1],pIn[2]); 330 pIn += 4; 331 } 332 return aRes; 333 } 334 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 335 { 336 const double* pIn( deviceColor.getConstArray() ); 337 const sal_Size nLen( deviceColor.getLength() ); 338 ENSURE_ARG_OR_THROW2(nLen%4==0, 339 "number of channels no multiple of 4", 340 static_cast<rendering::XColorSpace*>(this), 0); 341 342 uno::Sequence< rendering::ARGBColor > aRes(nLen/4); 343 rendering::ARGBColor* pOut( aRes.getArray() ); 344 for( sal_Size i=0; i<nLen; i+=4 ) 345 { 346 *pOut++ = rendering::ARGBColor(pIn[3],pIn[3]*pIn[0],pIn[3]*pIn[1],pIn[3]*pIn[2]); 347 pIn += 4; 348 } 349 return aRes; 350 } 351 virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 352 { 353 const rendering::RGBColor* pIn( rgbColor.getConstArray() ); 354 const sal_Size nLen( rgbColor.getLength() ); 355 356 uno::Sequence< double > aRes(nLen*4); 357 double* pColors=aRes.getArray(); 358 for( sal_Size i=0; i<nLen; ++i ) 359 { 360 *pColors++ = pIn->Red; 361 *pColors++ = pIn->Green; 362 *pColors++ = pIn->Blue; 363 *pColors++ = 1.0; 364 ++pIn; 365 } 366 return aRes; 367 } 368 virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 369 { 370 const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); 371 const sal_Size nLen( rgbColor.getLength() ); 372 373 uno::Sequence< double > aRes(nLen*4); 374 double* pColors=aRes.getArray(); 375 for( sal_Size i=0; i<nLen; ++i ) 376 { 377 *pColors++ = pIn->Red; 378 *pColors++ = pIn->Green; 379 *pColors++ = pIn->Blue; 380 *pColors++ = pIn->Alpha; 381 ++pIn; 382 } 383 return aRes; 384 } 385 virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 386 { 387 const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); 388 const sal_Size nLen( rgbColor.getLength() ); 389 390 uno::Sequence< double > aRes(nLen*4); 391 double* pColors=aRes.getArray(); 392 for( sal_Size i=0; i<nLen; ++i ) 393 { 394 *pColors++ = pIn->Red/pIn->Alpha; 395 *pColors++ = pIn->Green/pIn->Alpha; 396 *pColors++ = pIn->Blue/pIn->Alpha; 397 *pColors++ = pIn->Alpha; 398 ++pIn; 399 } 400 return aRes; 401 } 402 403 // XIntegerBitmapColorSpace 404 virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) throw (uno::RuntimeException) 405 { 406 return 32; 407 } 408 virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) throw (uno::RuntimeException) 409 { 410 return maBitCounts; 411 } 412 virtual ::sal_Int8 SAL_CALL getEndianness( ) throw (uno::RuntimeException) 413 { 414 return util::Endianness::LITTLE; 415 } 416 virtual uno::Sequence<double> SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, 417 const uno::Reference< rendering::XColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, 418 uno::RuntimeException) 419 { 420 if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) ) 421 { 422 const sal_Int8* pIn( deviceColor.getConstArray() ); 423 const sal_Size nLen( deviceColor.getLength() ); 424 ENSURE_ARG_OR_THROW2(nLen%4==0, 425 "number of channels no multiple of 4", 426 static_cast<rendering::XColorSpace*>(this), 0); 427 428 uno::Sequence<double> aRes(nLen); 429 double* pOut( aRes.getArray() ); 430 for( sal_Size i=0; i<nLen; i+=4 ) 431 { 432 *pOut++ = vcl::unotools::toDoubleColor(*pIn++); 433 *pOut++ = vcl::unotools::toDoubleColor(*pIn++); 434 *pOut++ = vcl::unotools::toDoubleColor(*pIn++); 435 *pOut++ = vcl::unotools::toDoubleColor(255-*pIn++); 436 } 437 return aRes; 438 } 439 else 440 { 441 // TODO(P3): if we know anything about target 442 // colorspace, this can be greatly sped up 443 uno::Sequence<rendering::ARGBColor> aIntermediate( 444 convertIntegerToARGB(deviceColor)); 445 return targetColorSpace->convertFromARGB(aIntermediate); 446 } 447 } 448 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& deviceColor, 449 const uno::Reference< rendering::XIntegerBitmapColorSpace >& targetColorSpace ) throw (lang::IllegalArgumentException, 450 uno::RuntimeException) 451 { 452 if( dynamic_cast<StandardColorSpace*>(targetColorSpace.get()) ) 453 { 454 // it's us, so simply pass-through the data 455 return deviceColor; 456 } 457 else 458 { 459 // TODO(P3): if we know anything about target 460 // colorspace, this can be greatly sped up 461 uno::Sequence<rendering::ARGBColor> aIntermediate( 462 convertIntegerToARGB(deviceColor)); 463 return targetColorSpace->convertIntegerFromARGB(aIntermediate); 464 } 465 } 466 virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 467 { 468 const sal_Int8* pIn( deviceColor.getConstArray() ); 469 const sal_Size nLen( deviceColor.getLength() ); 470 ENSURE_ARG_OR_THROW2(nLen%4==0, 471 "number of channels no multiple of 4", 472 static_cast<rendering::XColorSpace*>(this), 0); 473 474 uno::Sequence< rendering::RGBColor > aRes(nLen/4); 475 rendering::RGBColor* pOut( aRes.getArray() ); 476 for( sal_Size i=0; i<nLen; i+=4 ) 477 { 478 *pOut++ = rendering::RGBColor( 479 vcl::unotools::toDoubleColor(pIn[0]), 480 vcl::unotools::toDoubleColor(pIn[1]), 481 vcl::unotools::toDoubleColor(pIn[2])); 482 pIn += 4; 483 } 484 return aRes; 485 } 486 487 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 488 { 489 const sal_Int8* pIn( deviceColor.getConstArray() ); 490 const sal_Size nLen( deviceColor.getLength() ); 491 ENSURE_ARG_OR_THROW2(nLen%4==0, 492 "number of channels no multiple of 4", 493 static_cast<rendering::XColorSpace*>(this), 0); 494 495 uno::Sequence< rendering::ARGBColor > aRes(nLen/4); 496 rendering::ARGBColor* pOut( aRes.getArray() ); 497 for( sal_Size i=0; i<nLen; i+=4 ) 498 { 499 *pOut++ = rendering::ARGBColor( 500 vcl::unotools::toDoubleColor(255-pIn[3]), 501 vcl::unotools::toDoubleColor(pIn[0]), 502 vcl::unotools::toDoubleColor(pIn[1]), 503 vcl::unotools::toDoubleColor(pIn[2])); 504 pIn += 4; 505 } 506 return aRes; 507 } 508 509 virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 510 { 511 const sal_Int8* pIn( deviceColor.getConstArray() ); 512 const sal_Size nLen( deviceColor.getLength() ); 513 ENSURE_ARG_OR_THROW2(nLen%4==0, 514 "number of channels no multiple of 4", 515 static_cast<rendering::XColorSpace*>(this), 0); 516 517 uno::Sequence< rendering::ARGBColor > aRes(nLen/4); 518 rendering::ARGBColor* pOut( aRes.getArray() ); 519 for( sal_Size i=0; i<nLen; i+=4 ) 520 { 521 const sal_Int8 nAlpha( 255-pIn[3] ); 522 *pOut++ = rendering::ARGBColor( 523 vcl::unotools::toDoubleColor(nAlpha), 524 vcl::unotools::toDoubleColor(nAlpha*pIn[0]), 525 vcl::unotools::toDoubleColor(nAlpha*pIn[1]), 526 vcl::unotools::toDoubleColor(nAlpha*pIn[2])); 527 pIn += 4; 528 } 529 return aRes; 530 } 531 532 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const uno::Sequence< rendering::RGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 533 { 534 const rendering::RGBColor* pIn( rgbColor.getConstArray() ); 535 const sal_Size nLen( rgbColor.getLength() ); 536 537 uno::Sequence< sal_Int8 > aRes(nLen*4); 538 sal_Int8* pColors=aRes.getArray(); 539 for( sal_Size i=0; i<nLen; ++i ) 540 { 541 *pColors++ = vcl::unotools::toByteColor(pIn->Red); 542 *pColors++ = vcl::unotools::toByteColor(pIn->Green); 543 *pColors++ = vcl::unotools::toByteColor(pIn->Blue); 544 *pColors++ = 0; 545 ++pIn; 546 } 547 return aRes; 548 } 549 550 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 551 { 552 const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); 553 const sal_Size nLen( rgbColor.getLength() ); 554 555 uno::Sequence< sal_Int8 > aRes(nLen*4); 556 sal_Int8* pColors=aRes.getArray(); 557 for( sal_Size i=0; i<nLen; ++i ) 558 { 559 *pColors++ = vcl::unotools::toByteColor(pIn->Red); 560 *pColors++ = vcl::unotools::toByteColor(pIn->Green); 561 *pColors++ = vcl::unotools::toByteColor(pIn->Blue); 562 *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha); 563 ++pIn; 564 } 565 return aRes; 566 } 567 568 virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& rgbColor ) throw (lang::IllegalArgumentException, uno::RuntimeException) 569 { 570 const rendering::ARGBColor* pIn( rgbColor.getConstArray() ); 571 const sal_Size nLen( rgbColor.getLength() ); 572 573 uno::Sequence< sal_Int8 > aRes(nLen*4); 574 sal_Int8* pColors=aRes.getArray(); 575 for( sal_Size i=0; i<nLen; ++i ) 576 { 577 *pColors++ = vcl::unotools::toByteColor(pIn->Red/pIn->Alpha); 578 *pColors++ = vcl::unotools::toByteColor(pIn->Green/pIn->Alpha); 579 *pColors++ = vcl::unotools::toByteColor(pIn->Blue/pIn->Alpha); 580 *pColors++ = 255-vcl::unotools::toByteColor(pIn->Alpha); 581 ++pIn; 582 } 583 return aRes; 584 } 585 586 public: 587 StandardColorSpace() : 588 maComponentTags(4), 589 maBitCounts(4) 590 { 591 sal_Int8* pTags = maComponentTags.getArray(); 592 sal_Int32* pBitCounts = maBitCounts.getArray(); 593 pTags[0] = rendering::ColorComponentTag::RGB_RED; 594 pTags[1] = rendering::ColorComponentTag::RGB_GREEN; 595 pTags[2] = rendering::ColorComponentTag::RGB_BLUE; 596 pTags[3] = rendering::ColorComponentTag::ALPHA; 597 598 pBitCounts[0] = 599 pBitCounts[1] = 600 pBitCounts[2] = 601 pBitCounts[3] = 8; 602 } 603 }; 604 605 struct StandardColorSpaceHolder : public rtl::StaticWithInit<uno::Reference<rendering::XIntegerBitmapColorSpace>, 606 StandardColorSpaceHolder> 607 { 608 uno::Reference<rendering::XIntegerBitmapColorSpace> operator()() 609 { 610 return new StandardColorSpace(); 611 } 612 }; 613 } 614 615 uno::Reference<rendering::XIntegerBitmapColorSpace> getStdColorSpace() 616 { 617 return StandardColorSpaceHolder::get(); 618 } 619 620 rendering::IntegerBitmapLayout getStdMemoryLayout( const geometry::IntegerSize2D& rBmpSize ) 621 { 622 rendering::IntegerBitmapLayout aLayout; 623 624 aLayout.ScanLines = rBmpSize.Height; 625 aLayout.ScanLineBytes = rBmpSize.Width*4; 626 aLayout.ScanLineStride = aLayout.ScanLineBytes; 627 aLayout.PlaneStride = 0; 628 aLayout.ColorSpace = getStdColorSpace(); 629 aLayout.Palette.clear(); 630 aLayout.IsMsbFirst = sal_False; 631 632 return aLayout; 633 } 634 635 ::Color stdIntSequenceToColor( const uno::Sequence<sal_Int8>& rColor ) 636 { 637 #ifdef OSL_BIGENDIAN 638 const sal_Int8* pCols( rColor.getConstArray() ); 639 return ::Color( pCols[3], pCols[0], pCols[1], pCols[2] ); 640 #else 641 return ::Color( *reinterpret_cast< const ::ColorData* >(rColor.getConstArray()) ); 642 #endif 643 } 644 645 uno::Sequence<sal_Int8> colorToStdIntSequence( const ::Color& rColor ) 646 { 647 uno::Sequence<sal_Int8> aRet(4); 648 sal_Int8* pCols( aRet.getArray() ); 649 #ifdef OSL_BIGENDIAN 650 pCols[0] = rColor.GetRed(); 651 pCols[1] = rColor.GetGreen(); 652 pCols[2] = rColor.GetBlue(); 653 pCols[3] = 255-rColor.GetTransparency(); 654 #else 655 *reinterpret_cast<sal_Int32*>(pCols) = rColor.GetColor(); 656 #endif 657 return aRet; 658 } 659 660 // Create a corrected view transformation out of the give one, 661 // which ensures that the rectangle given by (0,0) and 662 // rSpriteSize is mapped with its left,top corner to (0,0) 663 // again. This is required to properly render sprite 664 // animations to buffer bitmaps. 665 ::basegfx::B2DHomMatrix& calcRectToOriginTransform( ::basegfx::B2DHomMatrix& o_transform, 666 const ::basegfx::B2DRange& i_srcRect, 667 const ::basegfx::B2DHomMatrix& i_transformation ) 668 { 669 if( i_srcRect.isEmpty() ) 670 return o_transform=i_transformation; 671 672 // transform by given transformation 673 ::basegfx::B2DRectangle aTransformedRect; 674 675 calcTransformedRectBounds( aTransformedRect, 676 i_srcRect, 677 i_transformation ); 678 679 // now move resulting left,top point of bounds to (0,0) 680 const basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( 681 -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); 682 683 // prepend to original transformation 684 o_transform = aCorrectedTransform * i_transformation; 685 686 return o_transform; 687 } 688 689 ::basegfx::B2DRange& calcTransformedRectBounds( ::basegfx::B2DRange& outRect, 690 const ::basegfx::B2DRange& inRect, 691 const ::basegfx::B2DHomMatrix& transformation ) 692 { 693 outRect.reset(); 694 695 if( inRect.isEmpty() ) 696 return outRect; 697 698 // transform all four extremal points of the rectangle, 699 // take bounding rect of those. 700 701 // transform left-top point 702 outRect.expand( transformation * inRect.getMinimum() ); 703 704 // transform bottom-right point 705 outRect.expand( transformation * inRect.getMaximum() ); 706 707 ::basegfx::B2DPoint aPoint; 708 709 // transform top-right point 710 aPoint.setX( inRect.getMaxX() ); 711 aPoint.setY( inRect.getMinY() ); 712 713 aPoint *= transformation; 714 outRect.expand( aPoint ); 715 716 // transform bottom-left point 717 aPoint.setX( inRect.getMinX() ); 718 aPoint.setY( inRect.getMaxY() ); 719 720 aPoint *= transformation; 721 outRect.expand( aPoint ); 722 723 // over and out. 724 return outRect; 725 } 726 727 ::basegfx::B2DHomMatrix& calcRectToRectTransform( ::basegfx::B2DHomMatrix& o_transform, 728 const ::basegfx::B2DRange& destRect, 729 const ::basegfx::B2DRange& srcRect, 730 const ::basegfx::B2DHomMatrix& transformation ) 731 { 732 if( srcRect.isEmpty() || 733 destRect.isEmpty() ) 734 { 735 return o_transform=transformation; 736 } 737 738 // transform inputRect by transformation 739 ::basegfx::B2DRectangle aTransformedRect; 740 calcTransformedRectBounds( aTransformedRect, 741 srcRect, 742 transformation ); 743 744 // now move resulting left,top point of bounds to (0,0) 745 basegfx::B2DHomMatrix aCorrectedTransform(basegfx::tools::createTranslateB2DHomMatrix( 746 -aTransformedRect.getMinX(), -aTransformedRect.getMinY())); 747 748 // scale to match outRect 749 const double xDenom( aTransformedRect.getWidth() ); 750 const double yDenom( aTransformedRect.getHeight() ); 751 if( xDenom != 0.0 && yDenom != 0.0 ) 752 aCorrectedTransform.scale( destRect.getWidth() / xDenom, 753 destRect.getHeight() / yDenom ); 754 // TODO(E2): error handling 755 756 // translate to final position 757 aCorrectedTransform.translate( destRect.getMinX(), 758 destRect.getMinY() ); 759 760 ::basegfx::B2DHomMatrix transform( transformation ); 761 o_transform = aCorrectedTransform * transform; 762 763 return o_transform; 764 } 765 766 bool isInside( const ::basegfx::B2DRange& rContainedRect, 767 const ::basegfx::B2DRange& rTransformRect, 768 const ::basegfx::B2DHomMatrix& rTransformation ) 769 { 770 if( rContainedRect.isEmpty() || rTransformRect.isEmpty() ) 771 return false; 772 773 ::basegfx::B2DPolygon aPoly( 774 ::basegfx::tools::createPolygonFromRect( rTransformRect ) ); 775 aPoly.transform( rTransformation ); 776 777 return ::basegfx::tools::isInside( aPoly, 778 ::basegfx::tools::createPolygonFromRect( 779 rContainedRect ), 780 true ); 781 } 782 783 namespace 784 { 785 bool clipAreaImpl( ::basegfx::B2IRange* o_pDestArea, 786 ::basegfx::B2IRange& io_rSourceArea, 787 ::basegfx::B2IPoint& io_rDestPoint, 788 const ::basegfx::B2IRange& rSourceBounds, 789 const ::basegfx::B2IRange& rDestBounds ) 790 { 791 const ::basegfx::B2IPoint aSourceTopLeft( 792 io_rSourceArea.getMinimum() ); 793 794 ::basegfx::B2IRange aLocalSourceArea( io_rSourceArea ); 795 796 // clip source area (which must be inside rSourceBounds) 797 aLocalSourceArea.intersect( rSourceBounds ); 798 799 if( aLocalSourceArea.isEmpty() ) 800 return false; 801 802 // calc relative new source area points (relative to orig 803 // source area) 804 const ::basegfx::B2IVector aUpperLeftOffset( 805 aLocalSourceArea.getMinimum()-aSourceTopLeft ); 806 const ::basegfx::B2IVector aLowerRightOffset( 807 aLocalSourceArea.getMaximum()-aSourceTopLeft ); 808 809 ::basegfx::B2IRange aLocalDestArea( io_rDestPoint + aUpperLeftOffset, 810 io_rDestPoint + aLowerRightOffset ); 811 812 // clip dest area (which must be inside rDestBounds) 813 aLocalDestArea.intersect( rDestBounds ); 814 815 if( aLocalDestArea.isEmpty() ) 816 return false; 817 818 // calc relative new dest area points (relative to orig 819 // source area) 820 const ::basegfx::B2IVector aDestUpperLeftOffset( 821 aLocalDestArea.getMinimum()-io_rDestPoint ); 822 const ::basegfx::B2IVector aDestLowerRightOffset( 823 aLocalDestArea.getMaximum()-io_rDestPoint ); 824 825 io_rSourceArea = ::basegfx::B2IRange( aSourceTopLeft + aDestUpperLeftOffset, 826 aSourceTopLeft + aDestLowerRightOffset ); 827 io_rDestPoint = aLocalDestArea.getMinimum(); 828 829 if( o_pDestArea ) 830 *o_pDestArea = aLocalDestArea; 831 832 return true; 833 } 834 } 835 836 bool clipScrollArea( ::basegfx::B2IRange& io_rSourceArea, 837 ::basegfx::B2IPoint& io_rDestPoint, 838 ::std::vector< ::basegfx::B2IRange >& o_ClippedAreas, 839 const ::basegfx::B2IRange& rBounds ) 840 { 841 ::basegfx::B2IRange aResultingDestArea; 842 843 // compute full destination area (to determine uninitialized 844 // areas below) 845 const ::basegfx::B2I64Tuple& rRange( io_rSourceArea.getRange() ); 846 ::basegfx::B2IRange aInputDestArea( io_rDestPoint.getX(), 847 io_rDestPoint.getY(), 848 (io_rDestPoint.getX() 849 + static_cast<sal_Int32>(rRange.getX())), 850 (io_rDestPoint.getY() 851 + static_cast<sal_Int32>(rRange.getY())) ); 852 // limit to output area (no point updating outside of it) 853 aInputDestArea.intersect( rBounds ); 854 855 // clip to rBounds 856 if( !clipAreaImpl( &aResultingDestArea, 857 io_rSourceArea, 858 io_rDestPoint, 859 rBounds, 860 rBounds ) ) 861 return false; 862 863 // finally, compute all areas clipped off the total 864 // destination area. 865 ::basegfx::computeSetDifference( o_ClippedAreas, 866 aInputDestArea, 867 aResultingDestArea ); 868 869 return true; 870 } 871 872 bool clipBlit( ::basegfx::B2IRange& io_rSourceArea, 873 ::basegfx::B2IPoint& io_rDestPoint, 874 const ::basegfx::B2IRange& rSourceBounds, 875 const ::basegfx::B2IRange& rDestBounds ) 876 { 877 return clipAreaImpl( NULL, 878 io_rSourceArea, 879 io_rDestPoint, 880 rSourceBounds, 881 rDestBounds ); 882 } 883 884 ::basegfx::B2IRange spritePixelAreaFromB2DRange( const ::basegfx::B2DRange& rRange ) 885 { 886 if( rRange.isEmpty() ) 887 return ::basegfx::B2IRange(); 888 889 const ::basegfx::B2IPoint aTopLeft( ::basegfx::fround( rRange.getMinX() ), 890 ::basegfx::fround( rRange.getMinY() ) ); 891 return ::basegfx::B2IRange( aTopLeft, 892 aTopLeft + ::basegfx::B2IPoint( 893 ::basegfx::fround( rRange.getWidth() ), 894 ::basegfx::fround( rRange.getHeight() ) ) ); 895 } 896 897 uno::Sequence< uno::Any >& getDeviceInfo( const uno::Reference< rendering::XCanvas >& i_rxCanvas, 898 uno::Sequence< uno::Any >& o_rxParams ) 899 { 900 o_rxParams.realloc( 0 ); 901 902 if( i_rxCanvas.is() ) 903 { 904 try 905 { 906 uno::Reference< rendering::XGraphicDevice > xDevice( i_rxCanvas->getDevice(), 907 uno::UNO_QUERY_THROW ); 908 909 uno::Reference< lang::XServiceInfo > xServiceInfo( xDevice, 910 uno::UNO_QUERY_THROW ); 911 uno::Reference< beans::XPropertySet > xPropSet( xDevice, 912 uno::UNO_QUERY_THROW ); 913 914 o_rxParams.realloc( 2 ); 915 916 o_rxParams[ 0 ] = uno::makeAny( xServiceInfo->getImplementationName() ); 917 o_rxParams[ 1 ] = uno::makeAny( xPropSet->getPropertyValue( 918 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DeviceHandle") ) ) ); 919 } 920 catch( uno::Exception& ) 921 { 922 // ignore, but return empty sequence 923 } 924 } 925 926 return o_rxParams; 927 } 928 929 awt::Rectangle getAbsoluteWindowRect( const awt::Rectangle& rRect, 930 const uno::Reference< awt::XWindow2 >& xWin ) 931 { 932 awt::Rectangle aRetVal( rRect ); 933 934 ::Window* pWindow = VCLUnoHelper::GetWindow(xWin); 935 if( pWindow ) 936 { 937 ::Point aPoint( aRetVal.X, 938 aRetVal.Y ); 939 940 aPoint = pWindow->OutputToScreenPixel( aPoint ); 941 942 aRetVal.X = aPoint.X(); 943 aRetVal.Y = aPoint.Y(); 944 } 945 946 return aRetVal; 947 } 948 949 ::basegfx::B2DPolyPolygon getBoundMarksPolyPolygon( const ::basegfx::B2DRange& rRange ) 950 { 951 ::basegfx::B2DPolyPolygon aPolyPoly; 952 ::basegfx::B2DPolygon aPoly; 953 954 const double nX0( rRange.getMinX() ); 955 const double nY0( rRange.getMinY() ); 956 const double nX1( rRange.getMaxX() ); 957 const double nY1( rRange.getMaxY() ); 958 959 aPoly.append( ::basegfx::B2DPoint( nX0+4, 960 nY0 ) ); 961 aPoly.append( ::basegfx::B2DPoint( nX0, 962 nY0 ) ); 963 aPoly.append( ::basegfx::B2DPoint( nX0, 964 nY0+4 ) ); 965 aPolyPoly.append( aPoly ); aPoly.clear(); 966 967 aPoly.append( ::basegfx::B2DPoint( nX1-4, 968 nY0 ) ); 969 aPoly.append( ::basegfx::B2DPoint( nX1, 970 nY0 ) ); 971 aPoly.append( ::basegfx::B2DPoint( nX1, 972 nY0+4 ) ); 973 aPolyPoly.append( aPoly ); aPoly.clear(); 974 975 aPoly.append( ::basegfx::B2DPoint( nX0+4, 976 nY1 ) ); 977 aPoly.append( ::basegfx::B2DPoint( nX0, 978 nY1 ) ); 979 aPoly.append( ::basegfx::B2DPoint( nX0, 980 nY1-4 ) ); 981 aPolyPoly.append( aPoly ); aPoly.clear(); 982 983 aPoly.append( ::basegfx::B2DPoint( nX1-4, 984 nY1 ) ); 985 aPoly.append( ::basegfx::B2DPoint( nX1, 986 nY1 ) ); 987 aPoly.append( ::basegfx::B2DPoint( nX1, 988 nY1-4 ) ); 989 aPolyPoly.append( aPoly ); 990 991 return aPolyPoly; 992 } 993 994 int calcGradientStepCount( ::basegfx::B2DHomMatrix& rTotalTransform, 995 const rendering::ViewState& viewState, 996 const rendering::RenderState& renderState, 997 const rendering::Texture& texture, 998 int nColorSteps ) 999 { 1000 // calculate overall texture transformation (directly from 1001 // texture to device space). 1002 ::basegfx::B2DHomMatrix aMatrix; 1003 1004 rTotalTransform.identity(); 1005 ::basegfx::unotools::homMatrixFromAffineMatrix( rTotalTransform, 1006 texture.AffineTransform ); 1007 ::canvas::tools::mergeViewAndRenderTransform(aMatrix, 1008 viewState, 1009 renderState); 1010 rTotalTransform *= aMatrix; // prepend total view/render transformation 1011 1012 // determine size of gradient in device coordinate system 1013 // (to e.g. determine sensible number of gradient steps) 1014 ::basegfx::B2DPoint aLeftTop( 0.0, 0.0 ); 1015 ::basegfx::B2DPoint aLeftBottom( 0.0, 1.0 ); 1016 ::basegfx::B2DPoint aRightTop( 1.0, 0.0 ); 1017 ::basegfx::B2DPoint aRightBottom( 1.0, 1.0 ); 1018 1019 aLeftTop *= rTotalTransform; 1020 aLeftBottom *= rTotalTransform; 1021 aRightTop *= rTotalTransform; 1022 aRightBottom*= rTotalTransform; 1023 1024 // longest line in gradient bound rect 1025 const int nGradientSize( 1026 static_cast<int>( 1027 ::std::max( 1028 ::basegfx::B2DVector(aRightBottom-aLeftTop).getLength(), 1029 ::basegfx::B2DVector(aRightTop-aLeftBottom).getLength() ) + 1.0 ) ); 1030 1031 // typical number for pixel of the same color (strip size) 1032 const int nStripSize( nGradientSize < 50 ? 2 : 4 ); 1033 1034 // use at least three steps, and at utmost the number of color 1035 // steps 1036 return ::std::max( 3, 1037 ::std::min( 1038 nGradientSize / nStripSize, 1039 nColorSteps ) ); 1040 } 1041 1042 } // namespace tools 1043 1044 } // namespace canvas 1045