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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_vcl.hxx" 24 25 #include <tools/vcompat.hxx> 26 #include <tools/urlobj.hxx> 27 #include <tools/debug.hxx> 28 #include <tools/stream.hxx> 29 #include <ucbhelper/content.hxx> 30 #include <unotools/ucbstreamhelper.hxx> 31 #include <unotools/tempfile.hxx> 32 #include <vcl/outdev.hxx> 33 #include <vcl/virdev.hxx> 34 #include <vcl/gfxlink.hxx> 35 #include <vcl/cvtgrf.hxx> 36 #include <vcl/salbtype.hxx> 37 #include <vcl/graph.hxx> 38 #include <vcl/metaact.hxx> 39 #include <impgraph.hxx> 40 #include <com/sun/star/ucb/CommandAbortedException.hpp> 41 #include <vcl/dibtools.hxx> 42 43 // ----------- 44 // - Defines - 45 // ----------- 46 47 #define GRAPHIC_MAXPARTLEN 256000L 48 #define GRAPHIC_MTFTOBMP_MAXEXT 2048 49 #define GRAPHIC_STREAMBUFSIZE 8192UL 50 51 #define SYS_WINMETAFILE 0x00000003L 52 #define SYS_WNTMETAFILE 0x00000004L 53 #define SYS_OS2METAFILE 0x00000005L 54 #define SYS_MACMETAFILE 0x00000006L 55 56 #define GRAPHIC_FORMAT_50 static_cast<sal_uInt32>(COMPAT_FORMAT( 'G', 'R', 'F', '5' )) 57 #define NATIVE_FORMAT_50 static_cast<sal_uInt32>(COMPAT_FORMAT( 'N', 'A', 'T', '5' )) 58 59 // --------------- 60 // - ImpSwapFile - 61 // --------------- 62 63 struct ImpSwapFile 64 { 65 INetURLObject aSwapURL; 66 sal_uLong nRefCount; 67 }; 68 69 // ----------------- 70 // - Graphicreader - 71 // ----------------- 72 73 class ReaderData 74 { 75 public: 76 Size maPreviewSize; 77 }; 78 79 GraphicReader::~GraphicReader() 80 { 81 delete mpReaderData; 82 } 83 84 // ------------------------------------------------------------------------ 85 86 sal_Bool GraphicReader::IsPreviewModeEnabled() const 87 { 88 if( !mpReaderData ) 89 return sal_False; 90 if( mpReaderData->maPreviewSize.Width() ) 91 return sal_True; 92 if( mpReaderData->maPreviewSize.Height() ) 93 return sal_True; 94 return sal_False; 95 } 96 97 // ------------------------------------------------------------------------ 98 99 void GraphicReader::DisablePreviewMode() 100 { 101 if( mpReaderData ) 102 mpReaderData->maPreviewSize = Size( 0, 0 ); 103 } 104 105 // ------------------------------------------------------------------------ 106 107 void GraphicReader::SetPreviewSize( const Size& rSize ) 108 { 109 if( !mpReaderData ) 110 mpReaderData = new ReaderData; 111 mpReaderData->maPreviewSize = rSize; 112 } 113 114 // ------------------------------------------------------------------------ 115 116 Size GraphicReader::GetPreviewSize() const 117 { 118 Size aSize( 0, 0 ); 119 if( mpReaderData ) 120 aSize = mpReaderData->maPreviewSize; 121 return aSize; 122 } 123 124 // -------------- 125 // - ImpGraphic - 126 // -------------- 127 128 ImpGraphic::ImpGraphic() : 129 mpAnimation ( NULL ), 130 mpContext ( NULL ), 131 mpSwapFile ( NULL ), 132 mpGfxLink ( NULL ), 133 meType ( GRAPHIC_NONE ), 134 mnDocFilePos ( 0UL ), 135 mnSizeBytes ( 0UL ), 136 mnRefCount ( 1UL ), 137 mbSwapOut ( sal_False ), 138 mbSwapUnderway ( sal_False ) 139 { 140 } 141 142 // ------------------------------------------------------------------------ 143 144 ImpGraphic::ImpGraphic( const ImpGraphic& rImpGraphic ) : 145 maMetaFile ( rImpGraphic.maMetaFile ), 146 maEx ( rImpGraphic.maEx ), 147 mpContext ( NULL ), 148 mpSwapFile ( rImpGraphic.mpSwapFile ), 149 meType ( rImpGraphic.meType ), 150 maDocFileURLStr ( rImpGraphic.maDocFileURLStr ), 151 mnDocFilePos ( rImpGraphic.mnDocFilePos ), 152 mnSizeBytes ( rImpGraphic.mnSizeBytes ), 153 mnRefCount ( 1UL ), 154 mbSwapOut ( rImpGraphic.mbSwapOut ), 155 mbSwapUnderway ( sal_False ) 156 { 157 if( mpSwapFile ) 158 mpSwapFile->nRefCount++; 159 160 if( rImpGraphic.mpGfxLink ) 161 mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink ); 162 else 163 mpGfxLink = NULL; 164 165 if( rImpGraphic.mpAnimation ) 166 { 167 mpAnimation = new Animation( *rImpGraphic.mpAnimation ); 168 maEx = mpAnimation->GetBitmapEx(); 169 } 170 else 171 mpAnimation = NULL; 172 173 maSvgData = rImpGraphic.maSvgData; 174 } 175 176 // ------------------------------------------------------------------------ 177 178 ImpGraphic::ImpGraphic( const Bitmap& rBitmap ) : 179 maEx ( rBitmap ), 180 mpAnimation ( NULL ), 181 mpContext ( NULL ), 182 mpSwapFile ( NULL ), 183 mpGfxLink ( NULL ), 184 meType ( !rBitmap ? GRAPHIC_NONE : GRAPHIC_BITMAP ), 185 mnDocFilePos ( 0UL ), 186 mnSizeBytes ( 0UL ), 187 mnRefCount ( 1UL ), 188 mbSwapOut ( sal_False ), 189 mbSwapUnderway ( sal_False ) 190 { 191 } 192 193 // ------------------------------------------------------------------------ 194 195 ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) : 196 maEx ( rBitmapEx ), 197 mpAnimation ( NULL ), 198 mpContext ( NULL ), 199 mpSwapFile ( NULL ), 200 mpGfxLink ( NULL ), 201 meType ( !rBitmapEx ? GRAPHIC_NONE : GRAPHIC_BITMAP ), 202 mnDocFilePos ( 0UL ), 203 mnSizeBytes ( 0UL ), 204 mnRefCount ( 1UL ), 205 mbSwapOut ( sal_False ), 206 mbSwapUnderway ( sal_False ) 207 { 208 } 209 210 // ------------------------------------------------------------------------ 211 212 ImpGraphic::ImpGraphic(const SvgDataPtr& rSvgDataPtr) 213 : mpAnimation( NULL ), 214 mpContext( NULL ), 215 mpSwapFile( NULL ), 216 mpGfxLink( NULL ), 217 meType( rSvgDataPtr.get() ? GRAPHIC_BITMAP : GRAPHIC_NONE ), 218 mnDocFilePos( 0UL ), 219 mnSizeBytes( 0UL ), 220 mnRefCount( 1UL ), 221 mbSwapOut( sal_False ), 222 mbSwapUnderway( sal_False ), 223 maSvgData(rSvgDataPtr) 224 { 225 } 226 227 // ------------------------------------------------------------------------ 228 229 ImpGraphic::ImpGraphic( const Animation& rAnimation ) : 230 maEx ( rAnimation.GetBitmapEx() ), 231 mpAnimation ( new Animation( rAnimation ) ), 232 mpContext ( NULL ), 233 mpSwapFile ( NULL ), 234 mpGfxLink ( NULL ), 235 meType ( GRAPHIC_BITMAP ), 236 mnDocFilePos ( 0UL ), 237 mnSizeBytes ( 0UL ), 238 mnRefCount ( 1UL ), 239 mbSwapOut ( sal_False ), 240 mbSwapUnderway ( sal_False ) 241 { 242 } 243 244 // ------------------------------------------------------------------------ 245 246 ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) : 247 maMetaFile ( rMtf ), 248 mpAnimation ( NULL ), 249 mpContext ( NULL ), 250 mpSwapFile ( NULL ), 251 mpGfxLink ( NULL ), 252 meType ( GRAPHIC_GDIMETAFILE ), 253 mnDocFilePos ( 0UL ), 254 mnSizeBytes ( 0UL ), 255 mnRefCount ( 1UL ), 256 mbSwapOut ( sal_False ), 257 mbSwapUnderway ( sal_False ) 258 { 259 } 260 261 // ------------------------------------------------------------------------ 262 263 ImpGraphic::~ImpGraphic() 264 { 265 ImplClear(); 266 267 if( (sal_uLong) mpContext > 1UL ) 268 delete mpContext; 269 } 270 271 // ------------------------------------------------------------------------ 272 273 ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic ) 274 { 275 if( &rImpGraphic != this ) 276 { 277 if( !mbSwapUnderway ) 278 ImplClear(); 279 280 maMetaFile = rImpGraphic.maMetaFile; 281 meType = rImpGraphic.meType; 282 mnSizeBytes = rImpGraphic.mnSizeBytes; 283 284 delete mpAnimation; 285 286 if ( rImpGraphic.mpAnimation ) 287 { 288 mpAnimation = new Animation( *rImpGraphic.mpAnimation ); 289 maEx = mpAnimation->GetBitmapEx(); 290 } 291 else 292 { 293 mpAnimation = NULL; 294 maEx = rImpGraphic.maEx; 295 } 296 297 if( !mbSwapUnderway ) 298 { 299 maDocFileURLStr = rImpGraphic.maDocFileURLStr; 300 mnDocFilePos = rImpGraphic.mnDocFilePos; 301 mbSwapOut = rImpGraphic.mbSwapOut; 302 mpSwapFile = rImpGraphic.mpSwapFile; 303 304 if( mpSwapFile ) 305 mpSwapFile->nRefCount++; 306 } 307 308 delete mpGfxLink; 309 310 if( rImpGraphic.mpGfxLink ) 311 mpGfxLink = new GfxLink( *rImpGraphic.mpGfxLink ); 312 else 313 mpGfxLink = NULL; 314 315 maSvgData = rImpGraphic.maSvgData; 316 } 317 318 return *this; 319 } 320 321 // ------------------------------------------------------------------------ 322 323 sal_Bool ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const 324 { 325 sal_Bool bRet = sal_False; 326 327 if( this == &rImpGraphic ) 328 bRet = sal_True; 329 else if( !ImplIsSwapOut() && ( rImpGraphic.meType == meType ) ) 330 { 331 switch( meType ) 332 { 333 case( GRAPHIC_NONE ): 334 bRet = sal_True; 335 break; 336 337 case( GRAPHIC_GDIMETAFILE ): 338 { 339 if( rImpGraphic.maMetaFile == maMetaFile ) 340 bRet = sal_True; 341 } 342 break; 343 344 case( GRAPHIC_BITMAP ): 345 { 346 if(maSvgData.get()) 347 { 348 if(maSvgData == rImpGraphic.maSvgData) 349 { 350 bRet = sal_True; 351 } 352 else if(rImpGraphic.maSvgData) 353 { 354 if(maSvgData->getSvgDataArrayLength() == rImpGraphic.maSvgData->getSvgDataArrayLength()) 355 { 356 if(0 == memcmp( 357 maSvgData->getSvgDataArray().get(), 358 rImpGraphic.maSvgData->getSvgDataArray().get(), 359 maSvgData->getSvgDataArrayLength())) 360 { 361 bRet = sal_True; 362 } 363 } 364 } 365 } 366 else if( mpAnimation ) 367 { 368 if( rImpGraphic.mpAnimation && ( *rImpGraphic.mpAnimation == *mpAnimation ) ) 369 bRet = sal_True; 370 } 371 else if( !rImpGraphic.mpAnimation && ( rImpGraphic.maEx == maEx ) ) 372 { 373 bRet = sal_True; 374 } 375 } 376 break; 377 378 default: 379 break; 380 } 381 } 382 383 return bRet; 384 } 385 386 // ------------------------------------------------------------------------ 387 388 void ImpGraphic::ImplClearGraphics( sal_Bool bCreateSwapInfo ) 389 { 390 if( bCreateSwapInfo && !ImplIsSwapOut() ) 391 { 392 maSwapInfo.maPrefMapMode = ImplGetPrefMapMode(); 393 maSwapInfo.maPrefSize = ImplGetPrefSize(); 394 } 395 396 maEx.Clear(); 397 maMetaFile.Clear(); 398 399 if( mpAnimation ) 400 { 401 mpAnimation->Clear(); 402 delete mpAnimation; 403 mpAnimation = NULL; 404 } 405 406 if( mpGfxLink ) 407 { 408 delete mpGfxLink; 409 mpGfxLink = NULL; 410 } 411 412 maSvgData.reset(); 413 } 414 415 // ------------------------------------------------------------------------ 416 417 void ImpGraphic::ImplClear() 418 { 419 if( mpSwapFile ) 420 { 421 if( mpSwapFile->nRefCount > 1 ) 422 mpSwapFile->nRefCount--; 423 else 424 { 425 try 426 { 427 ::ucbhelper::Content aCnt( mpSwapFile->aSwapURL.GetMainURL( INetURLObject::NO_DECODE ), 428 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 429 430 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 431 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 432 } 433 catch( const ::com::sun::star::ucb::ContentCreationException& ) 434 { 435 } 436 catch( const ::com::sun::star::uno::RuntimeException& ) 437 { 438 } 439 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 440 { 441 } 442 catch( const ::com::sun::star::uno::Exception& ) 443 { 444 } 445 446 delete mpSwapFile; 447 } 448 449 mpSwapFile = NULL; 450 } 451 452 mbSwapOut = sal_False; 453 mnDocFilePos = 0UL; 454 maDocFileURLStr.Erase(); 455 456 // cleanup 457 ImplClearGraphics( sal_False ); 458 meType = GRAPHIC_NONE; 459 mnSizeBytes = 0; 460 } 461 462 // ------------------------------------------------------------------------ 463 464 GraphicType ImpGraphic::ImplGetType() const 465 { 466 return meType; 467 } 468 469 // ------------------------------------------------------------------------ 470 471 void ImpGraphic::ImplSetDefaultType() 472 { 473 ImplClear(); 474 meType = GRAPHIC_DEFAULT; 475 } 476 477 // ------------------------------------------------------------------------ 478 479 sal_Bool ImpGraphic::ImplIsSupportedGraphic() const 480 { 481 return( meType != GRAPHIC_NONE ); 482 } 483 484 // ------------------------------------------------------------------------ 485 486 sal_Bool ImpGraphic::ImplIsTransparent() const 487 { 488 sal_Bool bRet(sal_True); 489 490 if( meType == GRAPHIC_BITMAP && !maSvgData.get()) 491 { 492 bRet = ( mpAnimation ? mpAnimation->IsTransparent() : maEx.IsTransparent() ); 493 } 494 495 return bRet; 496 } 497 498 // ------------------------------------------------------------------------ 499 500 sal_Bool ImpGraphic::ImplIsAlpha() const 501 { 502 sal_Bool bRet(sal_False); 503 504 if(maSvgData.get()) 505 { 506 bRet = sal_True; 507 } 508 else if( meType == GRAPHIC_BITMAP ) 509 { 510 bRet = ( NULL == mpAnimation ) && maEx.IsAlpha(); 511 } 512 513 return bRet; 514 } 515 516 // ------------------------------------------------------------------------ 517 518 sal_Bool ImpGraphic::ImplIsAnimated() const 519 { 520 return( mpAnimation != NULL ); 521 } 522 523 // ------------------------------------------------------------------------ 524 525 sal_Bool ImpGraphic::ImplIsEPS() const 526 { 527 return( ( meType == GRAPHIC_GDIMETAFILE ) && 528 ( maMetaFile.GetActionCount() > 0 ) && 529 ( maMetaFile.GetAction( 0 )->GetType() == META_EPS_ACTION ) ); 530 } 531 532 // ------------------------------------------------------------------------ 533 534 Bitmap ImpGraphic::ImplGetBitmap(const GraphicConversionParameters& rParameters) const 535 { 536 Bitmap aRetBmp; 537 538 if( meType == GRAPHIC_BITMAP ) 539 { 540 if(maSvgData.get() && maEx.IsEmpty()) 541 { 542 // use maEx as local buffer for rendered svg 543 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 544 } 545 546 const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx ); 547 const Color aReplaceColor( COL_WHITE ); 548 549 aRetBmp = rRetBmpEx.GetBitmap( &aReplaceColor ); 550 551 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height()) 552 aRetBmp.Scale(rParameters.getSizePixel()); 553 } 554 else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() ) 555 { 556 if(maEx.IsEmpty()) 557 { 558 // calculate size 559 VirtualDevice aVDev; 560 Size aDrawSize(aVDev.LogicToPixel(maMetaFile.GetPrefSize(), maMetaFile.GetPrefMapMode())); 561 562 if(rParameters.getSizePixel().Width() && rParameters.getSizePixel().Height()) 563 { 564 // apply given size if exists 565 aDrawSize = rParameters.getSizePixel(); 566 } 567 568 if(aDrawSize.Width() && aDrawSize.Height() && !rParameters.getUnlimitedSize() 569 && (aDrawSize.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aDrawSize.Height() > GRAPHIC_MTFTOBMP_MAXEXT)) 570 { 571 // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT 572 double fWH((double)aDrawSize.Width() / (double)aDrawSize.Height()); 573 574 if(fWH <= 1.0) 575 { 576 aDrawSize.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT * fWH)); 577 aDrawSize.setHeight(GRAPHIC_MTFTOBMP_MAXEXT); 578 } 579 else 580 { 581 aDrawSize.setWidth(GRAPHIC_MTFTOBMP_MAXEXT); 582 aDrawSize.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT / fWH)); 583 } 584 } 585 586 // calculate pixel size. Normally, it's the same as aDrawSize, but may 587 // need to be extended when hairlines are on the right or bottom edge 588 Size aPixelSize(aDrawSize); 589 590 if(GRAPHIC_GDIMETAFILE == ImplGetType()) 591 { 592 // get hairline and full bound rect 593 Rectangle aHairlineRect; 594 const Rectangle aRect(maMetaFile.GetBoundRect(aVDev, &aHairlineRect)); 595 596 if(!aRect.IsEmpty() && !aHairlineRect.IsEmpty()) 597 { 598 // expand if needed to allow bottom and right hairlines to be added 599 if(aRect.Right() == aHairlineRect.Right()) 600 { 601 aPixelSize.setWidth(aPixelSize.getWidth() + 1); 602 } 603 604 if(aRect.Bottom() == aHairlineRect.Bottom()) 605 { 606 aPixelSize.setHeight(aPixelSize.getHeight() + 1); 607 } 608 } 609 } 610 611 if(aVDev.SetOutputSizePixel(aPixelSize)) 612 { 613 if(rParameters.getAntiAliase()) 614 { 615 aVDev.SetAntialiasing(aVDev.GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW); 616 } 617 618 if(rParameters.getSnapHorVerLines()) 619 { 620 aVDev.SetAntialiasing(aVDev.GetAntialiasing() | ANTIALIASING_PIXELSNAPHAIRLINE); 621 } 622 623 ImplDraw( &aVDev, Point(), aDrawSize ); 624 625 // use maEx as local buffer for rendered metafile 626 const_cast< ImpGraphic* >(this)->maEx = aVDev.GetBitmap( Point(), aVDev.GetOutputSizePixel() ); 627 } 628 } 629 630 aRetBmp = maEx.GetBitmap(); 631 } 632 633 if( !!aRetBmp ) 634 { 635 aRetBmp.SetPrefMapMode( ImplGetPrefMapMode() ); 636 aRetBmp.SetPrefSize( ImplGetPrefSize() ); 637 } 638 639 return aRetBmp; 640 } 641 642 // ------------------------------------------------------------------------ 643 644 BitmapEx ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const 645 { 646 BitmapEx aRetBmpEx; 647 648 if( meType == GRAPHIC_BITMAP ) 649 { 650 if(maSvgData.get() && maEx.IsEmpty()) 651 { 652 // use maEx as local buffer for rendered svg 653 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 654 } 655 656 aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maEx ); 657 658 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height()) 659 { 660 aRetBmpEx.Scale( 661 rParameters.getSizePixel(), 662 rParameters.getScaleHighQuality() ? BMP_SCALE_BESTQUALITY : BMP_SCALE_FASTESTINTERPOLATE); 663 } 664 } 665 else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() ) 666 { 667 if(maEx.IsEmpty()) 668 { 669 const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) ); 670 671 // use maEx as local buffer for rendered metafile 672 const_cast< ImpGraphic* >(this)->maEx = BitmapEx(ImplGetBitmap(rParameters), aMonoMask.ImplGetBitmap(rParameters)); 673 } 674 675 aRetBmpEx = maEx; 676 } 677 678 return aRetBmpEx; 679 } 680 681 // ------------------------------------------------------------------------ 682 683 Animation ImpGraphic::ImplGetAnimation() const 684 { 685 Animation aAnimation; 686 687 if( mpAnimation ) 688 aAnimation = *mpAnimation; 689 690 return aAnimation; 691 } 692 693 // ------------------------------------------------------------------------ 694 695 const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const 696 { 697 if(GRAPHIC_BITMAP == meType && !maMetaFile.GetActionCount()) 698 { 699 // #119735# 700 // Use the local maMetaFile as container for a metafile-representation 701 // of the bitmap graphic. This will be done only once, thus be buffered. 702 // I checked all usages of maMetaFile, it is only used when type is not 703 // GRAPHIC_BITMAP. In operator= it will get copied, thus buffering will 704 // survive copying (change this if not wanted) 705 ImpGraphic* pThat = const_cast< ImpGraphic* >(this); 706 707 if(maSvgData.get() && !maEx) 708 { 709 // use maEx as local buffer for rendered svg 710 pThat->maEx = maSvgData->getReplacement(); 711 } 712 713 VirtualDevice aVirDev; 714 const Size aSizePixel(maEx.GetSizePixel()); 715 716 pThat->maMetaFile.Record(&aVirDev); 717 718 if(maEx.IsTransparent()) 719 { 720 aVirDev.DrawBitmapEx(Point(), maEx); 721 } 722 else 723 { 724 aVirDev.DrawBitmap(Point(), maEx.GetBitmap()); 725 } 726 727 pThat->maMetaFile.Stop(); 728 pThat->maMetaFile.SetPrefSize(aSizePixel); 729 } 730 731 return maMetaFile; 732 } 733 734 // ------------------------------------------------------------------------ 735 736 Size ImpGraphic::ImplGetPrefSize() const 737 { 738 Size aSize; 739 740 if( ImplIsSwapOut() ) 741 aSize = maSwapInfo.maPrefSize; 742 else 743 { 744 switch( meType ) 745 { 746 case( GRAPHIC_NONE ): 747 case( GRAPHIC_DEFAULT ): 748 break; 749 750 case( GRAPHIC_BITMAP ): 751 { 752 if(maSvgData.get() && maEx.IsEmpty()) 753 { 754 // svg not yet buffered in maEx, return size derived from range 755 const basegfx::B2DRange& rRange = maSvgData->getRange(); 756 757 aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight())); 758 } 759 else 760 { 761 aSize = maEx.GetPrefSize(); 762 763 if( !aSize.Width() || !aSize.Height() ) 764 { 765 aSize = maEx.GetSizePixel(); 766 } 767 } 768 } 769 break; 770 771 default: 772 { 773 if( ImplIsSupportedGraphic() ) 774 aSize = maMetaFile.GetPrefSize(); 775 } 776 break; 777 } 778 } 779 780 return aSize; 781 } 782 783 // ------------------------------------------------------------------------ 784 785 void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize ) 786 { 787 switch( meType ) 788 { 789 case( GRAPHIC_NONE ): 790 case( GRAPHIC_DEFAULT ): 791 break; 792 793 case( GRAPHIC_BITMAP ): 794 { 795 // #108077# Push through pref size to animation object, 796 // will be lost on copy otherwise 797 if(maSvgData.get()) 798 { 799 // ignore for Svg. If this is really used (except the grfcache) 800 // it can be extended by using maEx as buffer for maSvgData->getReplacement() 801 } 802 else 803 { 804 if( ImplIsAnimated() ) 805 { 806 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize( rPrefSize ); 807 } 808 809 maEx.SetPrefSize( rPrefSize ); 810 } 811 } 812 break; 813 814 default: 815 { 816 if( ImplIsSupportedGraphic() ) 817 maMetaFile.SetPrefSize( rPrefSize ); 818 } 819 break; 820 } 821 } 822 823 // ------------------------------------------------------------------------ 824 825 MapMode ImpGraphic::ImplGetPrefMapMode() const 826 { 827 MapMode aMapMode; 828 829 if( ImplIsSwapOut() ) 830 aMapMode = maSwapInfo.maPrefMapMode; 831 else 832 { 833 switch( meType ) 834 { 835 case( GRAPHIC_NONE ): 836 case( GRAPHIC_DEFAULT ): 837 break; 838 839 case( GRAPHIC_BITMAP ): 840 { 841 if(maSvgData.get() && maEx.IsEmpty()) 842 { 843 // svg not yet buffered in maEx, return default PrefMapMode 844 aMapMode = MapMode(MAP_100TH_MM); 845 } 846 else 847 { 848 const Size aSize( maEx.GetPrefSize() ); 849 850 if ( aSize.Width() && aSize.Height() ) 851 aMapMode = maEx.GetPrefMapMode(); 852 } 853 } 854 break; 855 856 default: 857 { 858 if( ImplIsSupportedGraphic() ) 859 return maMetaFile.GetPrefMapMode(); 860 } 861 break; 862 } 863 } 864 865 return aMapMode; 866 } 867 868 // ------------------------------------------------------------------------ 869 870 void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode ) 871 { 872 switch( meType ) 873 { 874 case( GRAPHIC_NONE ): 875 case( GRAPHIC_DEFAULT ): 876 break; 877 878 case( GRAPHIC_BITMAP ): 879 { 880 if(maSvgData.get()) 881 { 882 // ignore for Svg. If this is really used (except the grfcache) 883 // it can be extended by using maEx as buffer for maSvgData->getReplacement() 884 } 885 else 886 { 887 // #108077# Push through pref mapmode to animation object, 888 // will be lost on copy otherwise 889 if( ImplIsAnimated() ) 890 { 891 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefMapMode( rPrefMapMode ); 892 } 893 894 maEx.SetPrefMapMode( rPrefMapMode ); 895 } 896 } 897 break; 898 899 default: 900 { 901 if( ImplIsSupportedGraphic() ) 902 maMetaFile.SetPrefMapMode( rPrefMapMode ); 903 } 904 break; 905 } 906 } 907 908 // ------------------------------------------------------------------------ 909 910 sal_uLong ImpGraphic::ImplGetSizeBytes() const 911 { 912 if( 0 == mnSizeBytes ) 913 { 914 if( meType == GRAPHIC_BITMAP ) 915 { 916 if(maSvgData.get()) 917 { 918 mnSizeBytes = maSvgData->getSvgDataArrayLength(); 919 } 920 else 921 { 922 mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maEx.GetSizeBytes(); 923 } 924 } 925 else if( meType == GRAPHIC_GDIMETAFILE ) 926 { 927 mnSizeBytes = maMetaFile.GetSizeBytes(); 928 } 929 } 930 931 return( mnSizeBytes ); 932 } 933 934 // ------------------------------------------------------------------------ 935 936 void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const 937 { 938 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 939 { 940 switch( meType ) 941 { 942 case( GRAPHIC_DEFAULT ): 943 break; 944 945 case( GRAPHIC_BITMAP ): 946 { 947 if(maSvgData.get() && !maEx) 948 { 949 // use maEx as local buffer for rendered svg 950 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 951 } 952 953 if ( mpAnimation ) 954 { 955 mpAnimation->Draw( pOutDev, rDestPt ); 956 } 957 else 958 { 959 maEx.Draw( pOutDev, rDestPt ); 960 } 961 } 962 break; 963 964 default: 965 ImplDraw( pOutDev, rDestPt, maMetaFile.GetPrefSize() ); 966 break; 967 } 968 } 969 } 970 971 // ------------------------------------------------------------------------ 972 973 void ImpGraphic::ImplDraw( OutputDevice* pOutDev, 974 const Point& rDestPt, const Size& rDestSize ) const 975 { 976 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 977 { 978 switch( meType ) 979 { 980 case( GRAPHIC_DEFAULT ): 981 break; 982 983 case( GRAPHIC_BITMAP ): 984 { 985 if(maSvgData.get() && maEx.IsEmpty()) 986 { 987 // use maEx as local buffer for rendered svg 988 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 989 } 990 991 if( mpAnimation ) 992 { 993 mpAnimation->Draw( pOutDev, rDestPt, rDestSize ); 994 } 995 else 996 { 997 maEx.Draw( pOutDev, rDestPt, rDestSize ); 998 } 999 } 1000 break; 1001 1002 default: 1003 { 1004 ( (ImpGraphic*) this )->maMetaFile.WindStart(); 1005 ( (ImpGraphic*) this )->maMetaFile.Play( pOutDev, rDestPt, rDestSize ); 1006 ( (ImpGraphic*) this )->maMetaFile.WindStart(); 1007 } 1008 break; 1009 } 1010 } 1011 } 1012 1013 // ------------------------------------------------------------------------ 1014 1015 void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, 1016 const Point& rDestPt, 1017 long nExtraData, 1018 OutputDevice* pFirstFrameOutDev ) 1019 { 1020 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1021 mpAnimation->Start( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev ); 1022 } 1023 1024 // ------------------------------------------------------------------------ 1025 1026 void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt, 1027 const Size& rDestSize, long nExtraData, 1028 OutputDevice* pFirstFrameOutDev ) 1029 { 1030 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1031 mpAnimation->Start( pOutDev, rDestPt, rDestSize, nExtraData, pFirstFrameOutDev ); 1032 } 1033 1034 // ------------------------------------------------------------------------ 1035 1036 void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData ) 1037 { 1038 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1039 mpAnimation->Stop( pOutDev, nExtraData ); 1040 } 1041 1042 // ------------------------------------------------------------------------ 1043 1044 void ImpGraphic::ImplSetAnimationNotifyHdl( const Link& rLink ) 1045 { 1046 if( mpAnimation ) 1047 mpAnimation->SetNotifyHdl( rLink ); 1048 } 1049 1050 // ------------------------------------------------------------------------ 1051 1052 Link ImpGraphic::ImplGetAnimationNotifyHdl() const 1053 { 1054 Link aLink; 1055 1056 if( mpAnimation ) 1057 aLink = mpAnimation->GetNotifyHdl(); 1058 1059 return aLink; 1060 } 1061 1062 // ------------------------------------------------------------------------ 1063 1064 sal_uLong ImpGraphic::ImplGetAnimationLoopCount() const 1065 { 1066 return( mpAnimation ? mpAnimation->GetLoopCount() : 0UL ); 1067 } 1068 1069 // ------------------------------------------------------------------------ 1070 1071 void ImpGraphic::ImplResetAnimationLoopCount() 1072 { 1073 if( mpAnimation ) 1074 mpAnimation->ResetLoopCount(); 1075 } 1076 1077 // ------------------------------------------------------------------------ 1078 1079 List* ImpGraphic::ImplGetAnimationInfoList() const 1080 { 1081 return( mpAnimation ? mpAnimation->GetAInfoList() : NULL ); 1082 } 1083 1084 // ------------------------------------------------------------------------ 1085 1086 GraphicReader* ImpGraphic::ImplGetContext() 1087 { 1088 return mpContext; 1089 } 1090 1091 // ------------------------------------------------------------------------ 1092 1093 void ImpGraphic::ImplSetContext( GraphicReader* pReader ) 1094 { 1095 mpContext = pReader; 1096 } 1097 1098 // ------------------------------------------------------------------------ 1099 1100 void ImpGraphic::ImplSetDocFileName( const String& rName, sal_uLong nFilePos ) 1101 { 1102 const INetURLObject aURL( rName ); 1103 1104 DBG_ASSERT( !rName.Len() || ( aURL.GetProtocol() != INET_PROT_NOT_VALID ), "Graphic::SetDocFileName(...): invalid URL" ); 1105 1106 maDocFileURLStr = aURL.GetMainURL( INetURLObject::NO_DECODE ); 1107 mnDocFilePos = nFilePos; 1108 } 1109 1110 // ------------------------------------------------------------------------ 1111 1112 const String& ImpGraphic::ImplGetDocFileName() const 1113 { 1114 return maDocFileURLStr; 1115 } 1116 1117 // ------------------------------------------------------------------------ 1118 1119 sal_uLong ImpGraphic::ImplGetDocFilePos() const 1120 { 1121 return mnDocFilePos; 1122 } 1123 1124 // ------------------------------------------------------------------------ 1125 1126 sal_Bool ImpGraphic::ImplReadEmbedded( SvStream& rIStm, sal_Bool bSwap ) 1127 { 1128 MapMode aMapMode; 1129 Size aSize; 1130 const sal_uLong nStartPos = rIStm.Tell(); 1131 sal_uInt32 nId; 1132 sal_uLong nHeaderLen; 1133 long nType; 1134 long nLen; 1135 const sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt(); 1136 sal_Bool bRet = sal_False; 1137 1138 if( !mbSwapUnderway ) 1139 { 1140 const String aTempURLStr( maDocFileURLStr ); 1141 const sal_uLong nTempPos = mnDocFilePos; 1142 1143 ImplClear(); 1144 1145 maDocFileURLStr = aTempURLStr; 1146 mnDocFilePos = nTempPos; 1147 } 1148 1149 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1150 rIStm >> nId; 1151 1152 // check version 1153 if( GRAPHIC_FORMAT_50 == nId ) 1154 { 1155 // read new style header 1156 VersionCompat* pCompat = new VersionCompat( rIStm, STREAM_READ ); 1157 1158 rIStm >> nType; 1159 rIStm >> nLen; 1160 rIStm >> aSize; 1161 rIStm >> aMapMode; 1162 1163 delete pCompat; 1164 } 1165 else 1166 { 1167 // read old style header 1168 long nWidth, nHeight; 1169 long nMapMode, nScaleNumX, nScaleDenomX; 1170 long nScaleNumY, nScaleDenomY, nOffsX, nOffsY; 1171 1172 rIStm.SeekRel( -4L ); 1173 1174 rIStm >> nType >> nLen >> nWidth >> nHeight; 1175 rIStm >> nMapMode >> nScaleNumX >> nScaleDenomX >> nScaleNumY; 1176 rIStm >> nScaleDenomY >> nOffsX >> nOffsY; 1177 1178 // swapped 1179 if( nType > 100L ) 1180 { 1181 nType = SWAPLONG( nType ); 1182 nLen = SWAPLONG( nLen ); 1183 nWidth = SWAPLONG( nWidth ); 1184 nHeight = SWAPLONG( nHeight ); 1185 nMapMode = SWAPLONG( nMapMode ); 1186 nScaleNumX = SWAPLONG( nScaleNumX ); 1187 nScaleDenomX = SWAPLONG( nScaleDenomX ); 1188 nScaleNumY = SWAPLONG( nScaleNumY ); 1189 nScaleDenomY = SWAPLONG( nScaleDenomY ); 1190 nOffsX = SWAPLONG( nOffsX ); 1191 nOffsY = SWAPLONG( nOffsY ); 1192 } 1193 1194 aSize = Size( nWidth, nHeight ); 1195 aMapMode = MapMode( (MapUnit) nMapMode, Point( nOffsX, nOffsY ), 1196 Fraction( nScaleNumX, nScaleDenomX ), 1197 Fraction( nScaleNumY, nScaleDenomY ) ); 1198 } 1199 1200 nHeaderLen = rIStm.Tell() - nStartPos; 1201 meType = (GraphicType) nType; 1202 1203 if( meType ) 1204 { 1205 if( meType == GRAPHIC_BITMAP ) 1206 { 1207 if(maSvgData.get() && maEx.IsEmpty()) 1208 { 1209 // use maEx as local buffer for rendered svg 1210 maEx = maSvgData->getReplacement(); 1211 } 1212 1213 maEx.aBitmapSize = aSize; 1214 1215 if( aMapMode != MapMode() ) 1216 { 1217 maEx.SetPrefMapMode( aMapMode ); 1218 maEx.SetPrefSize( aSize ); 1219 } 1220 } 1221 else 1222 { 1223 maMetaFile.SetPrefMapMode( aMapMode ); 1224 maMetaFile.SetPrefSize( aSize ); 1225 } 1226 1227 if( bSwap ) 1228 { 1229 if( maDocFileURLStr.Len() ) 1230 { 1231 rIStm.Seek( nStartPos + nHeaderLen + nLen ); 1232 bRet = mbSwapOut = sal_True; 1233 } 1234 else 1235 { 1236 ::utl::TempFile aTempFile; 1237 const INetURLObject aTmpURL( aTempFile.GetURL() ); 1238 1239 if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() ) 1240 { 1241 SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1242 1243 if( pOStm ) 1244 { 1245 sal_uLong nFullLen = nHeaderLen + nLen; 1246 sal_uLong nPartLen = Min( nFullLen, (sal_uLong) GRAPHIC_MAXPARTLEN ); 1247 sal_uInt8* pBuffer = (sal_uInt8*) rtl_allocateMemory( nPartLen ); 1248 1249 pOStm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1250 1251 if( pBuffer ) 1252 { 1253 rIStm.Seek( nStartPos ); 1254 1255 while( nFullLen ) 1256 { 1257 rIStm.Read( (char*) pBuffer, nPartLen ); 1258 pOStm->Write( (char*) pBuffer, nPartLen ); 1259 1260 nFullLen -= nPartLen; 1261 1262 if( nFullLen < GRAPHIC_MAXPARTLEN ) 1263 nPartLen = nFullLen; 1264 } 1265 1266 rtl_freeMemory( pBuffer ); 1267 sal_uLong nReadErr = rIStm.GetError(), nWriteErr = pOStm->GetError(); 1268 delete pOStm, pOStm = NULL; 1269 1270 if( !nReadErr && !nWriteErr ) 1271 { 1272 bRet = mbSwapOut = sal_True; 1273 mpSwapFile = new ImpSwapFile; 1274 mpSwapFile->nRefCount = 1; 1275 mpSwapFile->aSwapURL = aTmpURL; 1276 } 1277 else 1278 { 1279 try 1280 { 1281 ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), 1282 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1283 1284 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1285 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1286 } 1287 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1288 { 1289 } 1290 catch( const ::com::sun::star::uno::RuntimeException& ) 1291 { 1292 } 1293 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1294 { 1295 } 1296 catch( const ::com::sun::star::uno::Exception& ) 1297 { 1298 } 1299 } 1300 } 1301 1302 delete pOStm; 1303 } 1304 } 1305 } 1306 } 1307 else if( meType == GRAPHIC_BITMAP || meType == GRAPHIC_GDIMETAFILE ) 1308 { 1309 rIStm >> *this; 1310 bRet = ( rIStm.GetError() == 0UL ); 1311 } 1312 else if( meType >= SYS_WINMETAFILE && meType <= SYS_MACMETAFILE ) 1313 { 1314 Graphic aSysGraphic; 1315 sal_uLong nCvtType; 1316 1317 switch( sal::static_int_cast<sal_uLong>(meType) ) 1318 { 1319 case( SYS_WINMETAFILE ): 1320 case( SYS_WNTMETAFILE ): nCvtType = CVT_WMF; break; 1321 case( SYS_OS2METAFILE ): nCvtType = CVT_MET; break; 1322 case( SYS_MACMETAFILE ): nCvtType = CVT_PCT; break; 1323 1324 default: 1325 nCvtType = CVT_UNKNOWN; 1326 break; 1327 } 1328 1329 if( nType && GraphicConverter::Import( rIStm, aSysGraphic, nCvtType ) == ERRCODE_NONE ) 1330 { 1331 *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() ); 1332 bRet = ( rIStm.GetError() == 0UL ); 1333 } 1334 else 1335 meType = GRAPHIC_DEFAULT; 1336 } 1337 1338 if( bRet ) 1339 { 1340 ImplSetPrefMapMode( aMapMode ); 1341 ImplSetPrefSize( aSize ); 1342 } 1343 } 1344 else 1345 bRet = sal_True; 1346 1347 rIStm.SetNumberFormatInt( nOldFormat ); 1348 1349 return bRet; 1350 } 1351 1352 // ------------------------------------------------------------------------ 1353 1354 sal_Bool ImpGraphic::ImplWriteEmbedded( SvStream& rOStm ) 1355 { 1356 sal_Bool bRet = sal_False; 1357 1358 if( ( meType != GRAPHIC_NONE ) && ( meType != GRAPHIC_DEFAULT ) && !ImplIsSwapOut() ) 1359 { 1360 const MapMode aMapMode( ImplGetPrefMapMode() ); 1361 const Size aSize( ImplGetPrefSize() ); 1362 const sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt(); 1363 sal_uLong nDataFieldPos; 1364 1365 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1366 1367 // write correct version ( old style/new style header ) 1368 if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) 1369 { 1370 // write ID for new format (5.0) 1371 rOStm << GRAPHIC_FORMAT_50; 1372 1373 // write new style header 1374 VersionCompat* pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); 1375 1376 rOStm << (long) meType; 1377 1378 // data size is updated later 1379 nDataFieldPos = rOStm.Tell(); 1380 rOStm << (long) 0; 1381 1382 rOStm << aSize; 1383 rOStm << aMapMode; 1384 1385 delete pCompat; 1386 } 1387 else 1388 { 1389 // write old style (<=4.0) header 1390 rOStm << (long) meType; 1391 1392 // data size is updated later 1393 nDataFieldPos = rOStm.Tell(); 1394 rOStm << (long) 0; 1395 1396 rOStm << (long) aSize.Width(); 1397 rOStm << (long) aSize.Height(); 1398 rOStm << (long) aMapMode.GetMapUnit(); 1399 rOStm << (long) aMapMode.GetScaleX().GetNumerator(); 1400 rOStm << (long) aMapMode.GetScaleX().GetDenominator(); 1401 rOStm << (long) aMapMode.GetScaleY().GetNumerator(); 1402 rOStm << (long) aMapMode.GetScaleY().GetDenominator(); 1403 rOStm << (long) aMapMode.GetOrigin().X(); 1404 rOStm << (long) aMapMode.GetOrigin().Y(); 1405 } 1406 1407 // write data block 1408 if( !rOStm.GetError() ) 1409 { 1410 const sal_uLong nDataStart = rOStm.Tell(); 1411 1412 if( ImplIsSupportedGraphic() ) 1413 rOStm << *this; 1414 1415 if( !rOStm.GetError() ) 1416 { 1417 const sal_uLong nStmPos2 = rOStm.Tell(); 1418 rOStm.Seek( nDataFieldPos ); 1419 rOStm << (long) ( nStmPos2 - nDataStart ); 1420 rOStm.Seek( nStmPos2 ); 1421 bRet = sal_True; 1422 } 1423 } 1424 1425 rOStm.SetNumberFormatInt( nOldFormat ); 1426 } 1427 1428 return bRet; 1429 } 1430 1431 // ------------------------------------------------------------------------ 1432 1433 sal_Bool ImpGraphic::ImplSwapOut() 1434 { 1435 sal_Bool bRet = sal_False; 1436 1437 if( !ImplIsSwapOut() ) 1438 { 1439 if( !maDocFileURLStr.Len() ) 1440 { 1441 ::utl::TempFile aTempFile; 1442 const INetURLObject aTmpURL( aTempFile.GetURL() ); 1443 1444 if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() ) 1445 { 1446 SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1447 1448 if( pOStm ) 1449 { 1450 pOStm->SetVersion( SOFFICE_FILEFORMAT_50 ); 1451 pOStm->SetCompressMode( COMPRESSMODE_NATIVE ); 1452 1453 if( ( bRet = ImplSwapOut( pOStm ) ) == sal_True ) 1454 { 1455 mpSwapFile = new ImpSwapFile; 1456 mpSwapFile->nRefCount = 1; 1457 mpSwapFile->aSwapURL = aTmpURL; 1458 } 1459 else 1460 { 1461 delete pOStm, pOStm = NULL; 1462 1463 try 1464 { 1465 ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), 1466 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1467 1468 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1469 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1470 } 1471 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1472 { 1473 } 1474 catch( const ::com::sun::star::uno::RuntimeException& ) 1475 { 1476 } 1477 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1478 { 1479 } 1480 catch( const ::com::sun::star::uno::Exception& ) 1481 { 1482 } 1483 } 1484 1485 delete pOStm; 1486 } 1487 } 1488 } 1489 else 1490 { 1491 ImplClearGraphics( sal_True ); 1492 bRet = mbSwapOut = sal_True; 1493 } 1494 } 1495 1496 return bRet; 1497 } 1498 1499 // ------------------------------------------------------------------------ 1500 1501 sal_Bool ImpGraphic::ImplSwapOut( SvStream* pOStm ) 1502 { 1503 sal_Bool bRet = sal_False; 1504 1505 if( pOStm ) 1506 { 1507 pOStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); 1508 1509 if( !pOStm->GetError() && ImplWriteEmbedded( *pOStm ) ) 1510 { 1511 pOStm->Flush(); 1512 1513 if( !pOStm->GetError() ) 1514 { 1515 ImplClearGraphics( sal_True ); 1516 bRet = mbSwapOut = sal_True; 1517 } 1518 } 1519 } 1520 else 1521 { 1522 ImplClearGraphics( sal_True ); 1523 bRet = mbSwapOut = sal_True; 1524 } 1525 1526 return bRet; 1527 } 1528 1529 // ------------------------------------------------------------------------ 1530 1531 sal_Bool ImpGraphic::ImplSwapIn() 1532 { 1533 sal_Bool bRet = sal_False; 1534 1535 if( ImplIsSwapOut() ) 1536 { 1537 String aSwapURL; 1538 1539 if( mpSwapFile ) 1540 aSwapURL = mpSwapFile->aSwapURL.GetMainURL( INetURLObject::NO_DECODE ); 1541 else 1542 aSwapURL = maDocFileURLStr; 1543 1544 if( aSwapURL.Len() ) 1545 { 1546 SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aSwapURL, STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1547 1548 if( pIStm ) 1549 { 1550 pIStm->SetVersion( SOFFICE_FILEFORMAT_50 ); 1551 pIStm->SetCompressMode( COMPRESSMODE_NATIVE ); 1552 1553 if( !mpSwapFile ) 1554 pIStm->Seek( mnDocFilePos ); 1555 1556 bRet = ImplSwapIn( pIStm ); 1557 delete pIStm; 1558 1559 if( mpSwapFile ) 1560 { 1561 if( mpSwapFile->nRefCount > 1 ) 1562 mpSwapFile->nRefCount--; 1563 else 1564 { 1565 try 1566 { 1567 ::ucbhelper::Content aCnt( aSwapURL, 1568 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1569 1570 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1571 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1572 } 1573 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1574 { 1575 } 1576 catch( const ::com::sun::star::uno::RuntimeException& ) 1577 { 1578 } 1579 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1580 { 1581 } 1582 catch( const ::com::sun::star::uno::Exception& ) 1583 { 1584 } 1585 1586 delete mpSwapFile; 1587 } 1588 1589 mpSwapFile = NULL; 1590 } 1591 } 1592 } 1593 } 1594 1595 return bRet; 1596 } 1597 1598 // ------------------------------------------------------------------------ 1599 1600 sal_Bool ImpGraphic::ImplSwapIn( SvStream* pIStm ) 1601 { 1602 sal_Bool bRet = sal_False; 1603 1604 if( pIStm ) 1605 { 1606 pIStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); 1607 1608 if( !pIStm->GetError() ) 1609 { 1610 mbSwapUnderway = sal_True; 1611 bRet = ImplReadEmbedded( *pIStm ); 1612 mbSwapUnderway = sal_False; 1613 1614 if( !bRet ) 1615 ImplClear(); 1616 else 1617 mbSwapOut = sal_False; 1618 } 1619 } 1620 1621 return bRet; 1622 } 1623 1624 // ------------------------------------------------------------------------ 1625 1626 sal_Bool ImpGraphic::ImplIsSwapOut() const 1627 { 1628 return mbSwapOut; 1629 } 1630 1631 // ------------------------------------------------------------------------ 1632 1633 void ImpGraphic::ImplSetLink( const GfxLink& rGfxLink ) 1634 { 1635 delete mpGfxLink; 1636 mpGfxLink = new GfxLink( rGfxLink ); 1637 1638 if( mpGfxLink->IsNative() ) 1639 mpGfxLink->SwapOut(); 1640 } 1641 1642 // ------------------------------------------------------------------------ 1643 1644 GfxLink ImpGraphic::ImplGetLink() 1645 { 1646 return( mpGfxLink ? *mpGfxLink : GfxLink() ); 1647 } 1648 1649 // ------------------------------------------------------------------------ 1650 1651 sal_Bool ImpGraphic::ImplIsLink() const 1652 { 1653 return ( mpGfxLink != NULL ) ? sal_True : sal_False; 1654 } 1655 1656 // ------------------------------------------------------------------------ 1657 1658 sal_uLong ImpGraphic::ImplGetChecksum() const 1659 { 1660 sal_uLong nRet = 0; 1661 1662 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 1663 { 1664 switch( meType ) 1665 { 1666 case( GRAPHIC_DEFAULT ): 1667 break; 1668 1669 case( GRAPHIC_BITMAP ): 1670 { 1671 if(maSvgData.get() && maEx.IsEmpty()) 1672 { 1673 // use maEx as local buffer for rendered svg 1674 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 1675 } 1676 1677 if( mpAnimation ) 1678 { 1679 nRet = mpAnimation->GetChecksum(); 1680 } 1681 else 1682 { 1683 nRet = maEx.GetChecksum(); 1684 } 1685 } 1686 break; 1687 1688 default: 1689 nRet = maMetaFile.GetChecksum(); 1690 break; 1691 } 1692 } 1693 1694 return nRet; 1695 } 1696 1697 // ------------------------------------------------------------------------ 1698 1699 sal_Bool ImpGraphic::ImplExportNative( SvStream& rOStm ) const 1700 { 1701 sal_Bool bResult = sal_False; 1702 1703 if( !rOStm.GetError() ) 1704 { 1705 if( !ImplIsSwapOut() ) 1706 { 1707 if( mpGfxLink && mpGfxLink->IsNative() ) 1708 bResult = mpGfxLink->ExportNative( rOStm ); 1709 else 1710 { 1711 rOStm << *this; 1712 bResult = ( rOStm.GetError() == ERRCODE_NONE ); 1713 } 1714 } 1715 else 1716 rOStm.SetError( SVSTREAM_GENERALERROR ); 1717 } 1718 1719 return bResult; 1720 } 1721 1722 // ------------------------------------------------------------------------ 1723 1724 const SvgDataPtr& ImpGraphic::getSvgData() const 1725 { 1726 return maSvgData; 1727 } 1728 1729 // ------------------------------------------------------------------------ 1730 1731 SvStream& operator>>( SvStream& rIStm, ImpGraphic& rImpGraphic ) 1732 { 1733 if( !rIStm.GetError() ) 1734 { 1735 const sal_uLong nStmPos1 = rIStm.Tell(); 1736 sal_uInt32 nTmp; 1737 1738 if ( !rImpGraphic.mbSwapUnderway ) 1739 rImpGraphic.ImplClear(); 1740 1741 // read Id 1742 rIStm >> nTmp; 1743 1744 // if there is no more data, avoid further expensive 1745 // reading which will create VDevs and other stuff, just to 1746 // read nothing. CAUTION: Eof is only true AFTER reading another 1747 // byte, a speciality of SvMemoryStream (!) 1748 if(!rIStm.GetError() && !rIStm.IsEof()) 1749 { 1750 if( NATIVE_FORMAT_50 == nTmp ) 1751 { 1752 Graphic aGraphic; 1753 GfxLink aLink; 1754 VersionCompat* pCompat; 1755 1756 // read compat info 1757 pCompat = new VersionCompat( rIStm, STREAM_READ ); 1758 delete pCompat; 1759 1760 rIStm >> aLink; 1761 1762 // set dummy link to avoid creation of additional link after filtering; 1763 // we set a default link to avoid unnecessary swapping of native data 1764 aGraphic.SetLink( GfxLink() ); 1765 1766 if( !rIStm.GetError() && aLink.LoadNative( aGraphic ) ) 1767 { 1768 // set link only, if no other link was set 1769 const sal_Bool bSetLink = ( rImpGraphic.mpGfxLink == NULL ); 1770 1771 // assign graphic 1772 rImpGraphic = *aGraphic.ImplGetImpGraphic(); 1773 1774 if( aLink.IsPrefMapModeValid() ) 1775 rImpGraphic.ImplSetPrefMapMode( aLink.GetPrefMapMode() ); 1776 1777 if( aLink.IsPrefSizeValid() ) 1778 rImpGraphic.ImplSetPrefSize( aLink.GetPrefSize() ); 1779 1780 if( bSetLink ) 1781 rImpGraphic.ImplSetLink( aLink ); 1782 } 1783 else 1784 { 1785 rIStm.Seek( nStmPos1 ); 1786 rIStm.SetError( ERRCODE_IO_WRONGFORMAT ); 1787 } 1788 } 1789 else 1790 { 1791 BitmapEx aBmpEx; 1792 const sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt(); 1793 1794 rIStm.SeekRel( -4 ); 1795 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1796 ReadDIBBitmapEx(aBmpEx, rIStm); 1797 1798 if( !rIStm.GetError() ) 1799 { 1800 sal_uInt32 nMagic1(0), nMagic2(0); 1801 sal_uLong nActPos = rIStm.Tell(); 1802 1803 rIStm >> nMagic1 >> nMagic2; 1804 rIStm.Seek( nActPos ); 1805 1806 rImpGraphic = ImpGraphic( aBmpEx ); 1807 1808 if( !rIStm.GetError() && ( 0x5344414e == nMagic1 ) && ( 0x494d4931 == nMagic2 ) ) 1809 { 1810 delete rImpGraphic.mpAnimation; 1811 rImpGraphic.mpAnimation = new Animation; 1812 rIStm >> *rImpGraphic.mpAnimation; 1813 1814 // #108077# manually set loaded BmpEx to Animation 1815 // (which skips loading its BmpEx if already done) 1816 rImpGraphic.mpAnimation->SetBitmapEx(aBmpEx); 1817 } 1818 else 1819 rIStm.ResetError(); 1820 } 1821 else 1822 { 1823 GDIMetaFile aMtf; 1824 1825 rIStm.Seek( nStmPos1 ); 1826 rIStm.ResetError(); 1827 rIStm >> aMtf; 1828 1829 if( !rIStm.GetError() ) 1830 { 1831 rImpGraphic = aMtf; 1832 } 1833 else 1834 { 1835 // try to stream in Svg defining data (length, byte array and evtl. path) 1836 // See below (operator<<) for more information 1837 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0')); 1838 sal_uInt32 nMagic; 1839 rIStm.Seek(nStmPos1); 1840 rIStm.ResetError(); 1841 rIStm >> nMagic; 1842 1843 if(nSvgMagic == nMagic) 1844 { 1845 sal_uInt32 mnSvgDataArrayLength(0); 1846 rIStm >> mnSvgDataArrayLength; 1847 1848 if(mnSvgDataArrayLength) 1849 { 1850 SvgDataArray aNewData(new sal_uInt8[mnSvgDataArrayLength]); 1851 UniString aPath; 1852 1853 rIStm.Read(aNewData.get(), mnSvgDataArrayLength); 1854 rIStm.ReadByteString(aPath); 1855 1856 if(!rIStm.GetError()) 1857 { 1858 SvgDataPtr aSvgDataPtr( 1859 new SvgData( 1860 aNewData, 1861 mnSvgDataArrayLength, 1862 rtl::OUString(aPath))); 1863 1864 rImpGraphic = aSvgDataPtr; 1865 } 1866 } 1867 } 1868 1869 rIStm.Seek(nStmPos1); 1870 } 1871 } 1872 1873 rIStm.SetNumberFormatInt( nOldFormat ); 1874 } 1875 } 1876 } 1877 1878 return rIStm; 1879 } 1880 1881 // ------------------------------------------------------------------------ 1882 1883 SvStream& operator<<( SvStream& rOStm, const ImpGraphic& rImpGraphic ) 1884 { 1885 if( !rOStm.GetError() ) 1886 { 1887 if( !rImpGraphic.ImplIsSwapOut() ) 1888 { 1889 if( ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) && 1890 ( rOStm.GetCompressMode() & COMPRESSMODE_NATIVE ) && 1891 rImpGraphic.mpGfxLink && rImpGraphic.mpGfxLink->IsNative() ) 1892 { 1893 VersionCompat* pCompat; 1894 1895 // native format 1896 rOStm << NATIVE_FORMAT_50; 1897 1898 // write compat info 1899 pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); 1900 delete pCompat; 1901 1902 rImpGraphic.mpGfxLink->SetPrefMapMode( rImpGraphic.ImplGetPrefMapMode() ); 1903 rImpGraphic.mpGfxLink->SetPrefSize( rImpGraphic.ImplGetPrefSize() ); 1904 rOStm << *rImpGraphic.mpGfxLink; 1905 } 1906 else 1907 { 1908 // own format 1909 const sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt(); 1910 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1911 1912 switch( rImpGraphic.ImplGetType() ) 1913 { 1914 case( GRAPHIC_NONE ): 1915 case( GRAPHIC_DEFAULT ): 1916 break; 1917 1918 case GRAPHIC_BITMAP: 1919 { 1920 if(rImpGraphic.getSvgData().get()) 1921 { 1922 // stream out Svg defining data (length, byte array and evtl. path) 1923 // this is used e.g. in swapping out graphic data and in transporting it over UNO API 1924 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be 1925 // no problem to extend it; only used at runtime 1926 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0')); 1927 1928 rOStm << nSvgMagic; 1929 rOStm << rImpGraphic.getSvgData()->getSvgDataArrayLength(); 1930 rOStm.Write(rImpGraphic.getSvgData()->getSvgDataArray().get(), rImpGraphic.getSvgData()->getSvgDataArrayLength()); 1931 rOStm.WriteByteString(rImpGraphic.getSvgData()->getPath()); 1932 } 1933 else if( rImpGraphic.ImplIsAnimated()) 1934 { 1935 rOStm << *rImpGraphic.mpAnimation; 1936 } 1937 else 1938 { 1939 WriteDIBBitmapEx(rImpGraphic.maEx, rOStm); 1940 } 1941 } 1942 break; 1943 1944 default: 1945 { 1946 if( rImpGraphic.ImplIsSupportedGraphic() ) 1947 rOStm << rImpGraphic.maMetaFile; 1948 } 1949 break; 1950 } 1951 1952 rOStm.SetNumberFormatInt( nOldFormat ); 1953 } 1954 } 1955 else 1956 rOStm.SetError( SVSTREAM_GENERALERROR ); 1957 } 1958 1959 return rOStm; 1960 } 1961