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