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