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