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_slideshow.hxx" 26 27 #include <canvas/debug.hxx> 28 #include <tools/diagnose_ex.h> 29 #include <canvas/canvastools.hxx> 30 31 #include <math.h> 32 33 #include <com/sun/star/beans/NamedValue.hpp> 34 #include <com/sun/star/awt/Rectangle.hpp> 35 #include <com/sun/star/animations/ValuePair.hpp> 36 #include <com/sun/star/drawing/FillStyle.hpp> 37 #include <com/sun/star/drawing/LineStyle.hpp> 38 #include <com/sun/star/awt/FontSlant.hpp> 39 40 #include <basegfx/polygon/b2dpolygon.hxx> 41 #include <basegfx/polygon/b2dpolygontools.hxx> 42 #include <basegfx/range/b2drange.hxx> 43 #include <basegfx/vector/b2dvector.hxx> 44 #include <basegfx/vector/b2ivector.hxx> 45 #include <basegfx/matrix/b2dhommatrix.hxx> 46 #include <basegfx/numeric/ftools.hxx> 47 #include <basegfx/tools/lerp.hxx> 48 #include <basegfx/matrix/b2dhommatrixtools.hxx> 49 50 #include <cppcanvas/basegfxfactory.hxx> 51 52 #include "unoview.hxx" 53 #include "smilfunctionparser.hxx" 54 #include "tools.hxx" 55 56 #include <limits> 57 58 59 using namespace ::com::sun::star; 60 61 namespace slideshow 62 { 63 namespace internal 64 { 65 namespace 66 { 67 class NamedValueStringComparator 68 { 69 public: NamedValueStringComparator(const::rtl::OUString & rSearchString)70 NamedValueStringComparator( const ::rtl::OUString& rSearchString ) : 71 mrSearchString( rSearchString ) 72 { 73 } 74 operator ()(const beans::NamedValue & rValue)75 bool operator()( const beans::NamedValue& rValue ) 76 { 77 return rValue.Name == mrSearchString; 78 } 79 80 private: 81 const ::rtl::OUString& mrSearchString; 82 }; 83 84 class NamedValueComparator 85 { 86 public: NamedValueComparator(const beans::NamedValue & rKey)87 NamedValueComparator( const beans::NamedValue& rKey ) : 88 mrKey( rKey ) 89 { 90 } 91 operator ()(const beans::NamedValue & rValue)92 bool operator()( const beans::NamedValue& rValue ) 93 { 94 return rValue.Name == mrKey.Name && rValue.Value == mrKey.Value; 95 } 96 97 private: 98 const beans::NamedValue& mrKey; 99 }; 100 getAttributedShapeTransformation(const::basegfx::B2DRectangle & rShapeBounds,const ShapeAttributeLayerSharedPtr & pAttr)101 ::basegfx::B2DHomMatrix getAttributedShapeTransformation( const ::basegfx::B2DRectangle& rShapeBounds, 102 const ShapeAttributeLayerSharedPtr& pAttr ) 103 { 104 ::basegfx::B2DHomMatrix aTransform; 105 const ::basegfx::B2DSize& rSize( rShapeBounds.getRange() ); 106 107 const double nShearX( pAttr->isShearXAngleValid() ? 108 pAttr->getShearXAngle() : 109 0.0 ); 110 const double nShearY( pAttr->isShearYAngleValid() ? 111 pAttr->getShearYAngle() : 112 0.0 ); 113 const double nRotation( pAttr->isRotationAngleValid() ? 114 pAttr->getRotationAngle()*M_PI/180.0 : 115 0.0 ); 116 117 // scale, shear and rotation pivot point is the shape 118 // center - adapt origin accordingly 119 aTransform.translate( -0.5, -0.5 ); 120 121 // ensure valid size (zero size will inevitably lead 122 // to a singular transformation matrix) 123 aTransform.scale( ::basegfx::pruneScaleValue( 124 rSize.getX() ), 125 ::basegfx::pruneScaleValue( 126 rSize.getY() ) ); 127 128 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) ); 129 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) ); 130 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) ); 131 132 if( bNeedRotation || bNeedShearX || bNeedShearY ) 133 { 134 if( bNeedShearX ) 135 aTransform.shearX( nShearX ); 136 137 if( bNeedShearY ) 138 aTransform.shearY( nShearY ); 139 140 if( bNeedRotation ) 141 aTransform.rotate( nRotation ); 142 } 143 144 // move left, top corner back to position of the 145 // shape. Since we've already translated the 146 // center of the shape to the origin (the 147 // translate( -0.5, -0.5 ) above), translate to 148 // center of final shape position here. 149 aTransform.translate( rShapeBounds.getCenterX(), 150 rShapeBounds.getCenterY() ); 151 152 return aTransform; 153 } 154 } 155 156 // Value extraction from Any 157 // ========================= 158 159 /// extract unary double value from Any extractValue(double & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr & rShape,const::basegfx::B2DVector & rSlideBounds)160 bool extractValue( double& o_rValue, 161 const uno::Any& rSourceAny, 162 const ShapeSharedPtr& rShape, 163 const ::basegfx::B2DVector& rSlideBounds ) 164 { 165 // try to extract numeric value (double, or smaller POD, like float or int) 166 if( (rSourceAny >>= o_rValue) ) 167 { 168 // succeeded 169 return true; 170 } 171 172 // try to extract string 173 ::rtl::OUString aString; 174 if( !(rSourceAny >>= aString) ) 175 return false; // nothing left to try 176 177 // parse the string into an ExpressionNode 178 try 179 { 180 // Parse string into ExpressionNode, eval node at time 0.0 181 o_rValue = (*SmilFunctionParser::parseSmilValue( 182 aString, 183 calcRelativeShapeBounds(rSlideBounds, 184 rShape->getBounds()) ))(0.0); 185 } 186 catch( ParseError& ) 187 { 188 return false; 189 } 190 191 return true; 192 } 193 194 /// extract enum/constant group value from Any extractValue(sal_Int32 & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr &,const::basegfx::B2DVector &)195 bool extractValue( sal_Int32& o_rValue, 196 const uno::Any& rSourceAny, 197 const ShapeSharedPtr& /*rShape*/, 198 const ::basegfx::B2DVector& /*rSlideBounds*/ ) 199 { 200 // try to extract numeric value (int, or smaller POD, like byte) 201 if( (rSourceAny >>= o_rValue) ) 202 { 203 // succeeded 204 return true; 205 } 206 207 // okay, no plain int. Maybe one of the domain-specific enums? 208 drawing::FillStyle eFillStyle; 209 if( (rSourceAny >>= eFillStyle) ) 210 { 211 o_rValue = sal::static_int_cast<sal_Int16>(eFillStyle); 212 213 // succeeded 214 return true; 215 } 216 217 drawing::LineStyle eLineStyle; 218 if( (rSourceAny >>= eLineStyle) ) 219 { 220 o_rValue = sal::static_int_cast<sal_Int16>(eLineStyle); 221 222 // succeeded 223 return true; 224 } 225 226 awt::FontSlant eFontSlant; 227 if( (rSourceAny >>= eFontSlant) ) 228 { 229 o_rValue = sal::static_int_cast<sal_Int16>(eFontSlant); 230 231 // succeeded 232 return true; 233 } 234 235 // nothing left to try. Failure 236 return false; 237 } 238 239 /// extract enum/constant group value from Any extractValue(sal_Int16 & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr & rShape,const::basegfx::B2DVector & rSlideBounds)240 bool extractValue( sal_Int16& o_rValue, 241 const uno::Any& rSourceAny, 242 const ShapeSharedPtr& rShape, 243 const ::basegfx::B2DVector& rSlideBounds ) 244 { 245 sal_Int32 aValue; 246 if( !extractValue(aValue,rSourceAny,rShape,rSlideBounds) ) 247 return false; 248 249 if( std::numeric_limits<sal_Int16>::max() < aValue || 250 std::numeric_limits<sal_Int16>::min() > aValue ) 251 { 252 return false; 253 } 254 255 o_rValue = static_cast<sal_Int16>(aValue); 256 257 return true; 258 } 259 260 /// extract color value from Any extractValue(RGBColor & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr &,const::basegfx::B2DVector &)261 bool extractValue( RGBColor& o_rValue, 262 const uno::Any& rSourceAny, 263 const ShapeSharedPtr& /*rShape*/, 264 const ::basegfx::B2DVector& /*rSlideBounds*/ ) 265 { 266 // try to extract numeric value (double, or smaller POD, like float or int) 267 { 268 double nTmp = 0; 269 if( (rSourceAny >>= nTmp) ) 270 { 271 sal_uInt32 aIntColor( static_cast< sal_uInt32 >(nTmp) ); 272 273 // TODO(F2): Handle color values correctly, here 274 o_rValue = unoColor2RGBColor( aIntColor ); 275 276 // succeeded 277 return true; 278 } 279 } 280 281 // try double sequence 282 { 283 uno::Sequence< double > aTmp; 284 if( (rSourceAny >>= aTmp) ) 285 { 286 ENSURE_OR_THROW( aTmp.getLength() == 3, 287 "extractValue(): inappropriate length for RGB color value" ); 288 289 o_rValue = RGBColor( aTmp[0], aTmp[1], aTmp[2] ); 290 291 // succeeded 292 return true; 293 } 294 } 295 296 // try sal_Int32 sequence 297 { 298 uno::Sequence< sal_Int32 > aTmp; 299 if( (rSourceAny >>= aTmp) ) 300 { 301 ENSURE_OR_THROW( aTmp.getLength() == 3, 302 "extractValue(): inappropriate length for RGB color value" ); 303 304 // truncate to byte 305 o_rValue = RGBColor( ::cppcanvas::makeColor( 306 static_cast<sal_uInt8>(aTmp[0]), 307 static_cast<sal_uInt8>(aTmp[1]), 308 static_cast<sal_uInt8>(aTmp[2]), 309 255 ) ); 310 311 // succeeded 312 return true; 313 } 314 } 315 316 // try sal_Int8 sequence 317 { 318 uno::Sequence< sal_Int8 > aTmp; 319 if( (rSourceAny >>= aTmp) ) 320 { 321 ENSURE_OR_THROW( aTmp.getLength() == 3, 322 "extractValue(): inappropriate length for RGB color value" ); 323 324 o_rValue = RGBColor( ::cppcanvas::makeColor( aTmp[0], aTmp[1], aTmp[2], 255 ) ); 325 326 // succeeded 327 return true; 328 } 329 } 330 331 // try to extract string 332 ::rtl::OUString aString; 333 if( !(rSourceAny >>= aString) ) 334 return false; // nothing left to try 335 336 // TODO(F2): Provide symbolic color values here 337 o_rValue = RGBColor( 0.5, 0.5, 0.5 ); 338 339 return true; 340 } 341 342 /// extract color value from Any extractValue(HSLColor & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr &,const::basegfx::B2DVector &)343 bool extractValue( HSLColor& o_rValue, 344 const uno::Any& rSourceAny, 345 const ShapeSharedPtr& /*rShape*/, 346 const ::basegfx::B2DVector& /*rSlideBounds*/ ) 347 { 348 // try double sequence 349 { 350 uno::Sequence< double > aTmp; 351 if( (rSourceAny >>= aTmp) ) 352 { 353 ENSURE_OR_THROW( aTmp.getLength() == 3, 354 "extractValue(): inappropriate length for HSL color value" ); 355 356 o_rValue = HSLColor( aTmp[0], aTmp[1], aTmp[2] ); 357 358 // succeeded 359 return true; 360 } 361 } 362 363 // try sal_Int8 sequence 364 { 365 uno::Sequence< sal_Int8 > aTmp; 366 if( (rSourceAny >>= aTmp) ) 367 { 368 ENSURE_OR_THROW( aTmp.getLength() == 3, 369 "extractValue(): inappropriate length for HSL color value" ); 370 371 o_rValue = HSLColor( aTmp[0]*360.0/255.0, aTmp[1]/255.0, aTmp[2]/255.0 ); 372 373 // succeeded 374 return true; 375 } 376 } 377 378 return false; // nothing left to try 379 } 380 381 /// extract plain string from Any extractValue(::rtl::OUString & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr &,const::basegfx::B2DVector &)382 bool extractValue( ::rtl::OUString& o_rValue, 383 const uno::Any& rSourceAny, 384 const ShapeSharedPtr& /*rShape*/, 385 const ::basegfx::B2DVector& /*rSlideBounds*/ ) 386 { 387 // try to extract string 388 if( !(rSourceAny >>= o_rValue) ) 389 return false; // nothing left to try 390 391 return true; 392 } 393 394 /// extract bool value from Any extractValue(bool & o_rValue,const uno::Any & rSourceAny,const ShapeSharedPtr &,const::basegfx::B2DVector &)395 bool extractValue( bool& o_rValue, 396 const uno::Any& rSourceAny, 397 const ShapeSharedPtr& /*rShape*/, 398 const ::basegfx::B2DVector& /*rSlideBounds*/ ) 399 { 400 sal_Bool nTmp = sal_Bool(); 401 // try to extract bool value 402 if( (rSourceAny >>= nTmp) ) 403 { 404 o_rValue = nTmp; 405 406 // succeeded 407 return true; 408 } 409 410 // try to extract string 411 ::rtl::OUString aString; 412 if( !(rSourceAny >>= aString) ) 413 return false; // nothing left to try 414 415 // we also take the strings "true" and "false", 416 // as well as "on" and "off" here 417 if( aString.equalsIgnoreAsciiCaseAscii("true") || 418 aString.equalsIgnoreAsciiCaseAscii("on") ) 419 { 420 o_rValue = true; 421 return true; 422 } 423 if( aString.equalsIgnoreAsciiCaseAscii("false") || 424 aString.equalsIgnoreAsciiCaseAscii("off") ) 425 { 426 o_rValue = false; 427 return true; 428 } 429 430 // ultimately failed. 431 return false; 432 } 433 434 /// extract double 2-tuple from Any extractValue(::basegfx::B2DTuple & o_rPair,const uno::Any & rSourceAny,const ShapeSharedPtr & rShape,const::basegfx::B2DVector & rSlideBounds)435 bool extractValue( ::basegfx::B2DTuple& o_rPair, 436 const uno::Any& rSourceAny, 437 const ShapeSharedPtr& rShape, 438 const ::basegfx::B2DVector& rSlideBounds ) 439 { 440 animations::ValuePair aPair; 441 442 if( !(rSourceAny >>= aPair) ) 443 return false; 444 445 double nFirst; 446 if( !extractValue( nFirst, aPair.First, rShape, rSlideBounds ) ) 447 return false; 448 449 double nSecond; 450 if( !extractValue( nSecond, aPair.Second, rShape, rSlideBounds ) ) 451 return false; 452 453 o_rPair.setX( nFirst ); 454 o_rPair.setY( nSecond ); 455 456 return true; 457 } 458 findNamedValue(uno::Sequence<beans::NamedValue> const & rSequence,const beans::NamedValue & rSearchKey)459 bool findNamedValue( uno::Sequence< beans::NamedValue > const& rSequence, 460 const beans::NamedValue& rSearchKey ) 461 { 462 const beans::NamedValue* pArray = rSequence.getConstArray(); 463 const size_t nLen( rSequence.getLength() ); 464 465 if( nLen == 0 ) 466 return false; 467 468 const beans::NamedValue* pFound = ::std::find_if( pArray, 469 pArray + nLen, 470 NamedValueComparator( rSearchKey ) ); 471 472 if( pFound == pArray + nLen ) 473 return false; 474 475 return true; 476 } 477 findNamedValue(beans::NamedValue * o_pRet,const uno::Sequence<beans::NamedValue> & rSequence,const::rtl::OUString & rSearchString)478 bool findNamedValue( beans::NamedValue* o_pRet, 479 const uno::Sequence< beans::NamedValue >& rSequence, 480 const ::rtl::OUString& rSearchString ) 481 { 482 const beans::NamedValue* pArray = rSequence.getConstArray(); 483 const size_t nLen( rSequence.getLength() ); 484 485 if( nLen == 0 ) 486 return false; 487 488 const beans::NamedValue* pFound = ::std::find_if( pArray, 489 pArray + nLen, 490 NamedValueStringComparator( rSearchString ) ); 491 if( pFound == pArray + nLen ) 492 return false; 493 494 if( o_pRet ) 495 *o_pRet = *pFound; 496 497 return true; 498 } 499 calcRelativeShapeBounds(const basegfx::B2DVector & rPageSize,const basegfx::B2DRange & rShapeBounds)500 basegfx::B2DRange calcRelativeShapeBounds( const basegfx::B2DVector& rPageSize, 501 const basegfx::B2DRange& rShapeBounds ) 502 { 503 return basegfx::B2DRange( rShapeBounds.getMinX() / rPageSize.getX(), 504 rShapeBounds.getMinY() / rPageSize.getY(), 505 rShapeBounds.getMaxX() / rPageSize.getX(), 506 rShapeBounds.getMaxY() / rPageSize.getY() ); 507 } 508 509 // TODO(F2): Currently, the positional attributes DO NOT mirror the XShape properties. 510 // First and foremost, this is because we must operate with the shape boundrect, 511 // not position and size (the conversion between logic rect, snap rect and boundrect 512 // are non-trivial for draw shapes, and I won't duplicate them here). Thus, shapes 513 // rotated on the page will still have 0.0 rotation angle, as the metafile 514 // representation fetched over the API is our default zero case. 515 getShapeTransformation(const::basegfx::B2DRectangle & rShapeBounds,const ShapeAttributeLayerSharedPtr & pAttr)516 ::basegfx::B2DHomMatrix getShapeTransformation( const ::basegfx::B2DRectangle& rShapeBounds, 517 const ShapeAttributeLayerSharedPtr& pAttr ) 518 { 519 if( !pAttr ) 520 { 521 const basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleTranslateB2DHomMatrix( 522 rShapeBounds.getWidth(), rShapeBounds.getHeight(), 523 rShapeBounds.getMinX(), rShapeBounds.getMinY())); 524 525 return aTransform; 526 } 527 else 528 { 529 return getAttributedShapeTransformation( rShapeBounds, 530 pAttr ); 531 } 532 } 533 getSpriteTransformation(const::basegfx::B2DVector & rPixelSize,const::basegfx::B2DVector & rOrigSize,const ShapeAttributeLayerSharedPtr & pAttr)534 ::basegfx::B2DHomMatrix getSpriteTransformation( const ::basegfx::B2DVector& rPixelSize, 535 const ::basegfx::B2DVector& rOrigSize, 536 const ShapeAttributeLayerSharedPtr& pAttr ) 537 { 538 ::basegfx::B2DHomMatrix aTransform; 539 540 if( pAttr ) 541 { 542 const double nShearX( pAttr->isShearXAngleValid() ? 543 pAttr->getShearXAngle() : 544 0.0 ); 545 const double nShearY( pAttr->isShearYAngleValid() ? 546 pAttr->getShearYAngle() : 547 0.0 ); 548 const double nRotation( pAttr->isRotationAngleValid() ? 549 pAttr->getRotationAngle()*M_PI/180.0 : 550 0.0 ); 551 552 // scale, shear and rotation pivot point is the 553 // sprite's pixel center - adapt origin accordingly 554 aTransform.translate( -0.5*rPixelSize.getX(), 555 -0.5*rPixelSize.getY() ); 556 557 const ::basegfx::B2DSize aSize( 558 pAttr->isWidthValid() ? pAttr->getWidth() : rOrigSize.getX(), 559 pAttr->isHeightValid() ? pAttr->getHeight() : rOrigSize.getY() ); 560 561 // ensure valid size (zero size will inevitably lead 562 // to a singular transformation matrix). 563 aTransform.scale( ::basegfx::pruneScaleValue( 564 aSize.getX() / 565 ::basegfx::pruneScaleValue( 566 rOrigSize.getX() ) ), 567 ::basegfx::pruneScaleValue( 568 aSize.getY() / 569 ::basegfx::pruneScaleValue( 570 rOrigSize.getY() ) ) ); 571 572 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) ); 573 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) ); 574 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) ); 575 576 if( bNeedRotation || bNeedShearX || bNeedShearY ) 577 { 578 if( bNeedShearX ) 579 aTransform.shearX( nShearX ); 580 581 if( bNeedShearY ) 582 aTransform.shearY( nShearY ); 583 584 if( bNeedRotation ) 585 aTransform.rotate( nRotation ); 586 } 587 588 // move left, top corner back to original position of 589 // the sprite (we've translated the center of the 590 // sprite to the origin above). 591 aTransform.translate( 0.5*rPixelSize.getX(), 592 0.5*rPixelSize.getY() ); 593 } 594 595 // return identity transform for un-attributed 596 // shapes. This renders the sprite as-is, in it's 597 // document-supplied size. 598 return aTransform; 599 } 600 getShapeUpdateArea(const::basegfx::B2DRectangle & rUnitBounds,const::basegfx::B2DHomMatrix & rShapeTransform,const ShapeAttributeLayerSharedPtr & pAttr)601 ::basegfx::B2DRectangle getShapeUpdateArea( const ::basegfx::B2DRectangle& rUnitBounds, 602 const ::basegfx::B2DHomMatrix& rShapeTransform, 603 const ShapeAttributeLayerSharedPtr& pAttr ) 604 { 605 ::basegfx::B2DHomMatrix aTransform; 606 607 if( pAttr && 608 pAttr->isCharScaleValid() && 609 fabs(pAttr->getCharScale()) > 1.0 ) 610 { 611 // enlarge shape bounds. Have to consider the worst 612 // case here (the text fully fills the shape) 613 614 const double nCharScale( pAttr->getCharScale() ); 615 616 // center of scaling is the middle of the shape 617 aTransform.translate( -0.5, -0.5 ); 618 aTransform.scale( nCharScale, nCharScale ); 619 aTransform.translate( 0.5, 0.5 ); 620 } 621 622 aTransform *= rShapeTransform; 623 624 ::basegfx::B2DRectangle aRes; 625 626 // apply shape transformation to unit rect 627 return ::canvas::tools::calcTransformedRectBounds( 628 aRes, 629 rUnitBounds, 630 aTransform ); 631 } 632 getShapeUpdateArea(const::basegfx::B2DRange & rUnitBounds,const::basegfx::B2DRange & rShapeBounds)633 ::basegfx::B2DRange getShapeUpdateArea( const ::basegfx::B2DRange& rUnitBounds, 634 const ::basegfx::B2DRange& rShapeBounds ) 635 { 636 return ::basegfx::B2DRectangle( 637 basegfx::tools::lerp( rShapeBounds.getMinX(), 638 rShapeBounds.getMaxX(), 639 rUnitBounds.getMinX() ), 640 basegfx::tools::lerp( rShapeBounds.getMinY(), 641 rShapeBounds.getMaxY(), 642 rUnitBounds.getMinY() ), 643 basegfx::tools::lerp( rShapeBounds.getMinX(), 644 rShapeBounds.getMaxX(), 645 rUnitBounds.getMaxX() ), 646 basegfx::tools::lerp( rShapeBounds.getMinY(), 647 rShapeBounds.getMaxY(), 648 rUnitBounds.getMaxY() ) ); 649 } 650 getShapePosSize(const::basegfx::B2DRectangle & rOrigBounds,const ShapeAttributeLayerSharedPtr & pAttr)651 ::basegfx::B2DRectangle getShapePosSize( const ::basegfx::B2DRectangle& rOrigBounds, 652 const ShapeAttributeLayerSharedPtr& pAttr ) 653 { 654 // an already empty shape bound need no further 655 // treatment. In fact, any changes applied below would 656 // actually remove the special empty state, thus, don't 657 // change! 658 if( !pAttr || 659 rOrigBounds.isEmpty() ) 660 { 661 return rOrigBounds; 662 } 663 else 664 { 665 // cannot use maBounds anymore, attributes might have been 666 // changed by now. 667 // Have to use absolute values here, as negative sizes 668 // (aka mirrored shapes) _still_ have the same bounds, 669 // only with mirrored content. 670 ::basegfx::B2DSize aSize; 671 aSize.setX( fabs( pAttr->isWidthValid() ? 672 pAttr->getWidth() : 673 rOrigBounds.getWidth() ) ); 674 aSize.setY( fabs( pAttr->isHeightValid() ? 675 pAttr->getHeight() : 676 rOrigBounds.getHeight() ) ); 677 678 ::basegfx::B2DPoint aPos; 679 aPos.setX( pAttr->isPosXValid() ? 680 pAttr->getPosX() : 681 rOrigBounds.getCenterX() ); 682 aPos.setY( pAttr->isPosYValid() ? 683 pAttr->getPosY() : 684 rOrigBounds.getCenterY() ); 685 686 // the positional attribute retrieved from the 687 // ShapeAttributeLayer actually denotes the _middle_ 688 // of the shape (do it as the PPTs do...) 689 return ::basegfx::B2DRectangle( aPos - 0.5*aSize, 690 aPos + 0.5*aSize ); 691 } 692 } 693 unoColor2RGBColor(sal_Int32 nColor)694 RGBColor unoColor2RGBColor( sal_Int32 nColor ) 695 { 696 return RGBColor( 697 ::cppcanvas::makeColor( 698 // convert from API color to IntSRGBA color 699 // (0xAARRGGBB -> 0xRRGGBBAA) 700 static_cast< sal_uInt8 >( nColor >> 16U ), 701 static_cast< sal_uInt8 >( nColor >> 8U ), 702 static_cast< sal_uInt8 >( nColor ), 703 static_cast< sal_uInt8 >( nColor >> 24U ) ) ); 704 } 705 RGBAColor2UnoColor(::cppcanvas::Color::IntSRGBA aColor)706 sal_Int32 RGBAColor2UnoColor( ::cppcanvas::Color::IntSRGBA aColor ) 707 { 708 return ::cppcanvas::makeColorARGB( 709 // convert from IntSRGBA color to API color 710 // (0xRRGGBBAA -> 0xAARRGGBB) 711 static_cast< sal_uInt8 >(0), 712 ::cppcanvas::getRed(aColor), 713 ::cppcanvas::getGreen(aColor), 714 ::cppcanvas::getBlue(aColor)); 715 } 716 717 /*sal_Int32 RGBAColor2UnoColor( ::cppcanvas::Color::IntSRGBA aColor ) 718 { 719 return ::cppcanvas::unMakeColor( 720 // convert from IntSRGBA color to API color 721 // (0xRRGGBBAA -> 0xAARRGGBB) 722 static_cast< sal_uInt8 >(0), 723 ::cppcanvas::getRed(aColor), 724 ::cppcanvas::getGreen(aColor), 725 ::cppcanvas::getBlue(aColor)); 726 }*/ 727 unSignedToSigned(sal_Int8 nInt)728 sal_Int8 unSignedToSigned(sal_Int8 nInt) 729 { 730 if(nInt < 0 ){ 731 sal_Int8 nInt2 = nInt >> 1U; 732 return nInt2; 733 }else{ 734 return nInt; 735 } 736 } 737 fillRect(const::cppcanvas::CanvasSharedPtr & rCanvas,const::basegfx::B2DRectangle & rRect,::cppcanvas::Color::IntSRGBA aFillColor)738 void fillRect( const ::cppcanvas::CanvasSharedPtr& rCanvas, 739 const ::basegfx::B2DRectangle& rRect, 740 ::cppcanvas::Color::IntSRGBA aFillColor ) 741 { 742 const ::basegfx::B2DPolygon aPoly( 743 ::basegfx::tools::createPolygonFromRect( rRect )); 744 745 ::cppcanvas::PolyPolygonSharedPtr pPolyPoly( 746 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( rCanvas, 747 aPoly ) ); 748 749 if( pPolyPoly ) 750 { 751 pPolyPoly->setRGBAFillColor( aFillColor ); 752 pPolyPoly->draw(); 753 } 754 } 755 initSlideBackground(const::cppcanvas::CanvasSharedPtr & rCanvas,const::basegfx::B2ISize & rSize)756 void initSlideBackground( const ::cppcanvas::CanvasSharedPtr& rCanvas, 757 const ::basegfx::B2ISize& rSize ) 758 { 759 ::cppcanvas::CanvasSharedPtr pCanvas( rCanvas->clone() ); 760 761 // set transformation to identitiy (->device pixel) 762 pCanvas->setTransformation( ::basegfx::B2DHomMatrix() ); 763 764 // #i42440# Fill the _full_ background in 765 // black. Since we had to extend the bitmap by one 766 // pixel, and the bitmap is initialized white, 767 // depending on the slide content a one pixel wide 768 // line will show to the bottom and the right. 769 fillRect( pCanvas, 770 ::basegfx::B2DRectangle( 0.0, 0.0, 771 rSize.getX(), 772 rSize.getY() ), 773 0x000000FFU ); 774 775 // fill the bounds rectangle in white. Subtract one pixel 776 // from both width and height, because the slide size is 777 // chosen one pixel larger than given by the drawing 778 // layer. This is because shapes with line style, that 779 // have the size of the slide would otherwise be cut 780 // off. OTOH, every other slide background (solid fill, 781 // gradient, bitmap) render one pixel less, thus revealing 782 // ugly white pixel to the right and the bottom. 783 fillRect( pCanvas, 784 ::basegfx::B2DRectangle( 0.0, 0.0, 785 rSize.getX()-1, 786 rSize.getY()-1 ), 787 0xFFFFFFFFU ); 788 } 789 getAPIShapeBounds(const uno::Reference<drawing::XShape> & xShape)790 ::basegfx::B2DRectangle getAPIShapeBounds( const uno::Reference< drawing::XShape >& xShape ) 791 { 792 uno::Reference< beans::XPropertySet > xPropSet( xShape, 793 uno::UNO_QUERY_THROW ); 794 // read bound rect 795 awt::Rectangle aTmpRect; 796 if( !(xPropSet->getPropertyValue( 797 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BoundRect") ) ) >>= aTmpRect) ) 798 { 799 ENSURE_OR_THROW( false, 800 "getAPIShapeBounds(): Could not get \"BoundRect\" property from shape" ); 801 } 802 803 return ::basegfx::B2DRectangle( aTmpRect.X, 804 aTmpRect.Y, 805 aTmpRect.X+aTmpRect.Width, 806 aTmpRect.Y+aTmpRect.Height ); 807 } 808 getAPIShapePrio(const uno::Reference<drawing::XShape> & xShape)809 double getAPIShapePrio( const uno::Reference< drawing::XShape >& xShape ) 810 { 811 uno::Reference< beans::XPropertySet > xPropSet( xShape, 812 uno::UNO_QUERY_THROW ); 813 // read prio 814 sal_Int32 nPrio(0); 815 if( !(xPropSet->getPropertyValue( 816 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZOrder") ) ) >>= nPrio) ) 817 { 818 ENSURE_OR_THROW( false, 819 "getAPIShapePrio(): Could not get \"ZOrder\" property from shape" ); 820 } 821 822 // TODO(F2): Check and adapt the range of possible values here. 823 // Maybe we can also take the total number of shapes here 824 return nPrio / 65535.0; 825 } 826 getSlideSizePixel(const basegfx::B2DVector & rSlideSize,const UnoViewSharedPtr & pView)827 basegfx::B2IVector getSlideSizePixel( const basegfx::B2DVector& rSlideSize, 828 const UnoViewSharedPtr& pView ) 829 { 830 ENSURE_OR_THROW(pView, "getSlideSizePixel(): invalid view"); 831 832 // determine transformed page bounds 833 const basegfx::B2DRange aRect( 0,0, 834 rSlideSize.getX(), 835 rSlideSize.getY() ); 836 basegfx::B2DRange aTmpRect; 837 canvas::tools::calcTransformedRectBounds( aTmpRect, 838 aRect, 839 pView->getTransformation() ); 840 841 // #i42440# Returned slide size is one pixel too small, as 842 // rendering happens one pixel to the right and below the 843 // actual bound rect. 844 return basegfx::B2IVector( 845 basegfx::fround( aTmpRect.getRange().getX() ) + 1, 846 basegfx::fround( aTmpRect.getRange().getY() ) + 1 ); 847 } 848 } 849 } 850