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 // #123983# directly create a metafile with the same PrefSize and PrefMapMode 714 // the bitmap has, this will be an always correct metafile 715 if(maEx.IsTransparent()) 716 { 717 pThat->maMetaFile.AddAction(new MetaBmpExScaleAction(Point(), maEx.GetPrefSize(), maEx)); 718 } 719 else 720 { 721 pThat->maMetaFile.AddAction(new MetaBmpScaleAction(Point(), maEx.GetPrefSize(), maEx.GetBitmap())); 722 } 723 724 pThat->maMetaFile.Stop(); 725 pThat->maMetaFile.WindStart(); 726 pThat->maMetaFile.SetPrefSize(maEx.GetPrefSize()); 727 pThat->maMetaFile.SetPrefMapMode(maEx.GetPrefMapMode()); 728 } 729 730 return maMetaFile; 731 } 732 733 // ------------------------------------------------------------------------ 734 735 Size ImpGraphic::ImplGetPrefSize() const 736 { 737 Size aSize; 738 739 if( ImplIsSwapOut() ) 740 aSize = maSwapInfo.maPrefSize; 741 else 742 { 743 switch( meType ) 744 { 745 case( GRAPHIC_NONE ): 746 case( GRAPHIC_DEFAULT ): 747 break; 748 749 case( GRAPHIC_BITMAP ): 750 { 751 if(maSvgData.get() && maEx.IsEmpty()) 752 { 753 // svg not yet buffered in maEx, return size derived from range 754 const basegfx::B2DRange& rRange = maSvgData->getRange(); 755 756 aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight())); 757 } 758 else 759 { 760 aSize = maEx.GetPrefSize(); 761 762 if( !aSize.Width() || !aSize.Height() ) 763 { 764 aSize = maEx.GetSizePixel(); 765 } 766 } 767 } 768 break; 769 770 default: 771 { 772 if( ImplIsSupportedGraphic() ) 773 aSize = maMetaFile.GetPrefSize(); 774 } 775 break; 776 } 777 } 778 779 return aSize; 780 } 781 782 // ------------------------------------------------------------------------ 783 784 void ImpGraphic::ImplSetPrefSize( const Size& rPrefSize ) 785 { 786 switch( meType ) 787 { 788 case( GRAPHIC_NONE ): 789 case( GRAPHIC_DEFAULT ): 790 break; 791 792 case( GRAPHIC_BITMAP ): 793 { 794 // #108077# Push through pref size to animation object, 795 // will be lost on copy otherwise 796 if(maSvgData.get()) 797 { 798 // ignore for Svg. If this is really used (except the grfcache) 799 // it can be extended by using maEx as buffer for maSvgData->getReplacement() 800 } 801 else 802 { 803 if( ImplIsAnimated() ) 804 { 805 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize( rPrefSize ); 806 } 807 808 maEx.SetPrefSize( rPrefSize ); 809 } 810 } 811 break; 812 813 default: 814 { 815 if( ImplIsSupportedGraphic() ) 816 maMetaFile.SetPrefSize( rPrefSize ); 817 } 818 break; 819 } 820 } 821 822 // ------------------------------------------------------------------------ 823 824 MapMode ImpGraphic::ImplGetPrefMapMode() const 825 { 826 MapMode aMapMode; 827 828 if( ImplIsSwapOut() ) 829 aMapMode = maSwapInfo.maPrefMapMode; 830 else 831 { 832 switch( meType ) 833 { 834 case( GRAPHIC_NONE ): 835 case( GRAPHIC_DEFAULT ): 836 break; 837 838 case( GRAPHIC_BITMAP ): 839 { 840 if(maSvgData.get() && maEx.IsEmpty()) 841 { 842 // svg not yet buffered in maEx, return default PrefMapMode 843 aMapMode = MapMode(MAP_100TH_MM); 844 } 845 else 846 { 847 const Size aSize( maEx.GetPrefSize() ); 848 849 if ( aSize.Width() && aSize.Height() ) 850 aMapMode = maEx.GetPrefMapMode(); 851 } 852 } 853 break; 854 855 default: 856 { 857 if( ImplIsSupportedGraphic() ) 858 return maMetaFile.GetPrefMapMode(); 859 } 860 break; 861 } 862 } 863 864 return aMapMode; 865 } 866 867 // ------------------------------------------------------------------------ 868 869 void ImpGraphic::ImplSetPrefMapMode( const MapMode& rPrefMapMode ) 870 { 871 switch( meType ) 872 { 873 case( GRAPHIC_NONE ): 874 case( GRAPHIC_DEFAULT ): 875 break; 876 877 case( GRAPHIC_BITMAP ): 878 { 879 if(maSvgData.get()) 880 { 881 // ignore for Svg. If this is really used (except the grfcache) 882 // it can be extended by using maEx as buffer for maSvgData->getReplacement() 883 } 884 else 885 { 886 // #108077# Push through pref mapmode to animation object, 887 // will be lost on copy otherwise 888 if( ImplIsAnimated() ) 889 { 890 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefMapMode( rPrefMapMode ); 891 } 892 893 maEx.SetPrefMapMode( rPrefMapMode ); 894 } 895 } 896 break; 897 898 default: 899 { 900 if( ImplIsSupportedGraphic() ) 901 maMetaFile.SetPrefMapMode( rPrefMapMode ); 902 } 903 break; 904 } 905 } 906 907 // ------------------------------------------------------------------------ 908 909 sal_uLong ImpGraphic::ImplGetSizeBytes() const 910 { 911 if( 0 == mnSizeBytes ) 912 { 913 if( meType == GRAPHIC_BITMAP ) 914 { 915 if(maSvgData.get()) 916 { 917 mnSizeBytes = maSvgData->getSvgDataArrayLength(); 918 } 919 else 920 { 921 mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maEx.GetSizeBytes(); 922 } 923 } 924 else if( meType == GRAPHIC_GDIMETAFILE ) 925 { 926 mnSizeBytes = maMetaFile.GetSizeBytes(); 927 } 928 } 929 930 return( mnSizeBytes ); 931 } 932 933 // ------------------------------------------------------------------------ 934 935 void ImpGraphic::ImplDraw( OutputDevice* pOutDev, const Point& rDestPt ) const 936 { 937 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 938 { 939 switch( meType ) 940 { 941 case( GRAPHIC_DEFAULT ): 942 break; 943 944 case( GRAPHIC_BITMAP ): 945 { 946 if(maSvgData.get() && !maEx) 947 { 948 // use maEx as local buffer for rendered svg 949 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 950 } 951 952 if ( mpAnimation ) 953 { 954 mpAnimation->Draw( pOutDev, rDestPt ); 955 } 956 else 957 { 958 maEx.Draw( pOutDev, rDestPt ); 959 } 960 } 961 break; 962 963 default: 964 ImplDraw( pOutDev, rDestPt, maMetaFile.GetPrefSize() ); 965 break; 966 } 967 } 968 } 969 970 // ------------------------------------------------------------------------ 971 972 void ImpGraphic::ImplDraw( OutputDevice* pOutDev, 973 const Point& rDestPt, const Size& rDestSize ) const 974 { 975 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 976 { 977 switch( meType ) 978 { 979 case( GRAPHIC_DEFAULT ): 980 break; 981 982 case( GRAPHIC_BITMAP ): 983 { 984 if(maSvgData.get() && maEx.IsEmpty()) 985 { 986 // use maEx as local buffer for rendered svg 987 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 988 } 989 990 if( mpAnimation ) 991 { 992 mpAnimation->Draw( pOutDev, rDestPt, rDestSize ); 993 } 994 else 995 { 996 maEx.Draw( pOutDev, rDestPt, rDestSize ); 997 } 998 } 999 break; 1000 1001 default: 1002 { 1003 ( (ImpGraphic*) this )->maMetaFile.WindStart(); 1004 ( (ImpGraphic*) this )->maMetaFile.Play( pOutDev, rDestPt, rDestSize ); 1005 ( (ImpGraphic*) this )->maMetaFile.WindStart(); 1006 } 1007 break; 1008 } 1009 } 1010 } 1011 1012 // ------------------------------------------------------------------------ 1013 1014 void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, 1015 const Point& rDestPt, 1016 long nExtraData, 1017 OutputDevice* pFirstFrameOutDev ) 1018 { 1019 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1020 mpAnimation->Start( pOutDev, rDestPt, nExtraData, pFirstFrameOutDev ); 1021 } 1022 1023 // ------------------------------------------------------------------------ 1024 1025 void ImpGraphic::ImplStartAnimation( OutputDevice* pOutDev, const Point& rDestPt, 1026 const Size& rDestSize, long nExtraData, 1027 OutputDevice* pFirstFrameOutDev ) 1028 { 1029 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1030 mpAnimation->Start( pOutDev, rDestPt, rDestSize, nExtraData, pFirstFrameOutDev ); 1031 } 1032 1033 // ------------------------------------------------------------------------ 1034 1035 void ImpGraphic::ImplStopAnimation( OutputDevice* pOutDev, long nExtraData ) 1036 { 1037 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() && mpAnimation ) 1038 mpAnimation->Stop( pOutDev, nExtraData ); 1039 } 1040 1041 // ------------------------------------------------------------------------ 1042 1043 void ImpGraphic::ImplSetAnimationNotifyHdl( const Link& rLink ) 1044 { 1045 if( mpAnimation ) 1046 mpAnimation->SetNotifyHdl( rLink ); 1047 } 1048 1049 // ------------------------------------------------------------------------ 1050 1051 Link ImpGraphic::ImplGetAnimationNotifyHdl() const 1052 { 1053 Link aLink; 1054 1055 if( mpAnimation ) 1056 aLink = mpAnimation->GetNotifyHdl(); 1057 1058 return aLink; 1059 } 1060 1061 // ------------------------------------------------------------------------ 1062 1063 sal_uLong ImpGraphic::ImplGetAnimationLoopCount() const 1064 { 1065 return( mpAnimation ? mpAnimation->GetLoopCount() : 0UL ); 1066 } 1067 1068 // ------------------------------------------------------------------------ 1069 1070 void ImpGraphic::ImplResetAnimationLoopCount() 1071 { 1072 if( mpAnimation ) 1073 mpAnimation->ResetLoopCount(); 1074 } 1075 1076 // ------------------------------------------------------------------------ 1077 1078 List* ImpGraphic::ImplGetAnimationInfoList() const 1079 { 1080 return( mpAnimation ? mpAnimation->GetAInfoList() : NULL ); 1081 } 1082 1083 // ------------------------------------------------------------------------ 1084 1085 GraphicReader* ImpGraphic::ImplGetContext() 1086 { 1087 return mpContext; 1088 } 1089 1090 // ------------------------------------------------------------------------ 1091 1092 void ImpGraphic::ImplSetContext( GraphicReader* pReader ) 1093 { 1094 mpContext = pReader; 1095 } 1096 1097 // ------------------------------------------------------------------------ 1098 1099 void ImpGraphic::ImplSetDocFileName( const String& rName, sal_uLong nFilePos ) 1100 { 1101 const INetURLObject aURL( rName ); 1102 1103 DBG_ASSERT( !rName.Len() || ( aURL.GetProtocol() != INET_PROT_NOT_VALID ), "Graphic::SetDocFileName(...): invalid URL" ); 1104 1105 maDocFileURLStr = aURL.GetMainURL( INetURLObject::NO_DECODE ); 1106 mnDocFilePos = nFilePos; 1107 } 1108 1109 // ------------------------------------------------------------------------ 1110 1111 const String& ImpGraphic::ImplGetDocFileName() const 1112 { 1113 return maDocFileURLStr; 1114 } 1115 1116 // ------------------------------------------------------------------------ 1117 1118 sal_uLong ImpGraphic::ImplGetDocFilePos() const 1119 { 1120 return mnDocFilePos; 1121 } 1122 1123 // ------------------------------------------------------------------------ 1124 1125 sal_Bool ImpGraphic::ImplReadEmbedded( SvStream& rIStm, sal_Bool bSwap ) 1126 { 1127 MapMode aMapMode; 1128 Size aSize; 1129 const sal_uLong nStartPos = rIStm.Tell(); 1130 sal_uInt32 nId; 1131 sal_uLong nHeaderLen; 1132 long nType; 1133 long nLen; 1134 const sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt(); 1135 sal_Bool bRet = sal_False; 1136 1137 if( !mbSwapUnderway ) 1138 { 1139 const String aTempURLStr( maDocFileURLStr ); 1140 const sal_uLong nTempPos = mnDocFilePos; 1141 1142 ImplClear(); 1143 1144 maDocFileURLStr = aTempURLStr; 1145 mnDocFilePos = nTempPos; 1146 } 1147 1148 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1149 rIStm >> nId; 1150 1151 // check version 1152 if( GRAPHIC_FORMAT_50 == nId ) 1153 { 1154 // read new style header 1155 VersionCompat* pCompat = new VersionCompat( rIStm, STREAM_READ ); 1156 1157 rIStm >> nType; 1158 rIStm >> nLen; 1159 rIStm >> aSize; 1160 rIStm >> aMapMode; 1161 1162 delete pCompat; 1163 } 1164 else 1165 { 1166 // read old style header 1167 long nWidth, nHeight; 1168 long nMapMode, nScaleNumX, nScaleDenomX; 1169 long nScaleNumY, nScaleDenomY, nOffsX, nOffsY; 1170 1171 rIStm.SeekRel( -4L ); 1172 1173 rIStm >> nType >> nLen >> nWidth >> nHeight; 1174 rIStm >> nMapMode >> nScaleNumX >> nScaleDenomX >> nScaleNumY; 1175 rIStm >> nScaleDenomY >> nOffsX >> nOffsY; 1176 1177 // swapped 1178 if( nType > 100L ) 1179 { 1180 nType = SWAPLONG( nType ); 1181 nLen = SWAPLONG( nLen ); 1182 nWidth = SWAPLONG( nWidth ); 1183 nHeight = SWAPLONG( nHeight ); 1184 nMapMode = SWAPLONG( nMapMode ); 1185 nScaleNumX = SWAPLONG( nScaleNumX ); 1186 nScaleDenomX = SWAPLONG( nScaleDenomX ); 1187 nScaleNumY = SWAPLONG( nScaleNumY ); 1188 nScaleDenomY = SWAPLONG( nScaleDenomY ); 1189 nOffsX = SWAPLONG( nOffsX ); 1190 nOffsY = SWAPLONG( nOffsY ); 1191 } 1192 1193 aSize = Size( nWidth, nHeight ); 1194 aMapMode = MapMode( (MapUnit) nMapMode, Point( nOffsX, nOffsY ), 1195 Fraction( nScaleNumX, nScaleDenomX ), 1196 Fraction( nScaleNumY, nScaleDenomY ) ); 1197 } 1198 1199 nHeaderLen = rIStm.Tell() - nStartPos; 1200 meType = (GraphicType) nType; 1201 1202 if( meType ) 1203 { 1204 if( meType == GRAPHIC_BITMAP ) 1205 { 1206 if(maSvgData.get() && maEx.IsEmpty()) 1207 { 1208 // use maEx as local buffer for rendered svg 1209 maEx = maSvgData->getReplacement(); 1210 } 1211 1212 maEx.aBitmapSize = aSize; 1213 1214 if( aMapMode != MapMode() ) 1215 { 1216 maEx.SetPrefMapMode( aMapMode ); 1217 maEx.SetPrefSize( aSize ); 1218 } 1219 } 1220 else 1221 { 1222 maMetaFile.SetPrefMapMode( aMapMode ); 1223 maMetaFile.SetPrefSize( aSize ); 1224 } 1225 1226 if( bSwap ) 1227 { 1228 if( maDocFileURLStr.Len() ) 1229 { 1230 rIStm.Seek( nStartPos + nHeaderLen + nLen ); 1231 bRet = mbSwapOut = sal_True; 1232 } 1233 else 1234 { 1235 ::utl::TempFile aTempFile; 1236 const INetURLObject aTmpURL( aTempFile.GetURL() ); 1237 1238 if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() ) 1239 { 1240 SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1241 1242 if( pOStm ) 1243 { 1244 sal_uLong nFullLen = nHeaderLen + nLen; 1245 sal_uLong nPartLen = Min( nFullLen, (sal_uLong) GRAPHIC_MAXPARTLEN ); 1246 sal_uInt8* pBuffer = (sal_uInt8*) rtl_allocateMemory( nPartLen ); 1247 1248 pOStm->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1249 1250 if( pBuffer ) 1251 { 1252 rIStm.Seek( nStartPos ); 1253 1254 while( nFullLen ) 1255 { 1256 rIStm.Read( (char*) pBuffer, nPartLen ); 1257 pOStm->Write( (char*) pBuffer, nPartLen ); 1258 1259 nFullLen -= nPartLen; 1260 1261 if( nFullLen < GRAPHIC_MAXPARTLEN ) 1262 nPartLen = nFullLen; 1263 } 1264 1265 rtl_freeMemory( pBuffer ); 1266 sal_uLong nReadErr = rIStm.GetError(), nWriteErr = pOStm->GetError(); 1267 delete pOStm, pOStm = NULL; 1268 1269 if( !nReadErr && !nWriteErr ) 1270 { 1271 bRet = mbSwapOut = sal_True; 1272 mpSwapFile = new ImpSwapFile; 1273 mpSwapFile->nRefCount = 1; 1274 mpSwapFile->aSwapURL = aTmpURL; 1275 } 1276 else 1277 { 1278 try 1279 { 1280 ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), 1281 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1282 1283 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1284 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1285 } 1286 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1287 { 1288 } 1289 catch( const ::com::sun::star::uno::RuntimeException& ) 1290 { 1291 } 1292 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1293 { 1294 } 1295 catch( const ::com::sun::star::uno::Exception& ) 1296 { 1297 } 1298 } 1299 } 1300 1301 delete pOStm; 1302 } 1303 } 1304 } 1305 } 1306 else if( meType == GRAPHIC_BITMAP || meType == GRAPHIC_GDIMETAFILE ) 1307 { 1308 rIStm >> *this; 1309 bRet = ( rIStm.GetError() == 0UL ); 1310 } 1311 else if( meType >= SYS_WINMETAFILE && meType <= SYS_MACMETAFILE ) 1312 { 1313 Graphic aSysGraphic; 1314 sal_uLong nCvtType; 1315 1316 switch( sal::static_int_cast<sal_uLong>(meType) ) 1317 { 1318 case( SYS_WINMETAFILE ): 1319 case( SYS_WNTMETAFILE ): nCvtType = CVT_WMF; break; 1320 case( SYS_OS2METAFILE ): nCvtType = CVT_MET; break; 1321 case( SYS_MACMETAFILE ): nCvtType = CVT_PCT; break; 1322 1323 default: 1324 nCvtType = CVT_UNKNOWN; 1325 break; 1326 } 1327 1328 if( nType && GraphicConverter::Import( rIStm, aSysGraphic, nCvtType ) == ERRCODE_NONE ) 1329 { 1330 *this = ImpGraphic( aSysGraphic.GetGDIMetaFile() ); 1331 bRet = ( rIStm.GetError() == 0UL ); 1332 } 1333 else 1334 meType = GRAPHIC_DEFAULT; 1335 } 1336 1337 if( bRet ) 1338 { 1339 ImplSetPrefMapMode( aMapMode ); 1340 ImplSetPrefSize( aSize ); 1341 } 1342 } 1343 else 1344 bRet = sal_True; 1345 1346 rIStm.SetNumberFormatInt( nOldFormat ); 1347 1348 return bRet; 1349 } 1350 1351 // ------------------------------------------------------------------------ 1352 1353 sal_Bool ImpGraphic::ImplWriteEmbedded( SvStream& rOStm ) 1354 { 1355 sal_Bool bRet = sal_False; 1356 1357 if( ( meType != GRAPHIC_NONE ) && ( meType != GRAPHIC_DEFAULT ) && !ImplIsSwapOut() ) 1358 { 1359 const MapMode aMapMode( ImplGetPrefMapMode() ); 1360 const Size aSize( ImplGetPrefSize() ); 1361 const sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt(); 1362 sal_uLong nDataFieldPos; 1363 1364 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1365 1366 // write correct version ( old style/new style header ) 1367 if( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) 1368 { 1369 // write ID for new format (5.0) 1370 rOStm << GRAPHIC_FORMAT_50; 1371 1372 // write new style header 1373 VersionCompat* pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); 1374 1375 rOStm << (long) meType; 1376 1377 // data size is updated later 1378 nDataFieldPos = rOStm.Tell(); 1379 rOStm << (long) 0; 1380 1381 rOStm << aSize; 1382 rOStm << aMapMode; 1383 1384 delete pCompat; 1385 } 1386 else 1387 { 1388 // write old style (<=4.0) header 1389 rOStm << (long) meType; 1390 1391 // data size is updated later 1392 nDataFieldPos = rOStm.Tell(); 1393 rOStm << (long) 0; 1394 1395 rOStm << (long) aSize.Width(); 1396 rOStm << (long) aSize.Height(); 1397 rOStm << (long) aMapMode.GetMapUnit(); 1398 rOStm << (long) aMapMode.GetScaleX().GetNumerator(); 1399 rOStm << (long) aMapMode.GetScaleX().GetDenominator(); 1400 rOStm << (long) aMapMode.GetScaleY().GetNumerator(); 1401 rOStm << (long) aMapMode.GetScaleY().GetDenominator(); 1402 rOStm << (long) aMapMode.GetOrigin().X(); 1403 rOStm << (long) aMapMode.GetOrigin().Y(); 1404 } 1405 1406 // write data block 1407 if( !rOStm.GetError() ) 1408 { 1409 const sal_uLong nDataStart = rOStm.Tell(); 1410 1411 if( ImplIsSupportedGraphic() ) 1412 rOStm << *this; 1413 1414 if( !rOStm.GetError() ) 1415 { 1416 const sal_uLong nStmPos2 = rOStm.Tell(); 1417 rOStm.Seek( nDataFieldPos ); 1418 rOStm << (long) ( nStmPos2 - nDataStart ); 1419 rOStm.Seek( nStmPos2 ); 1420 bRet = sal_True; 1421 } 1422 } 1423 1424 rOStm.SetNumberFormatInt( nOldFormat ); 1425 } 1426 1427 return bRet; 1428 } 1429 1430 // ------------------------------------------------------------------------ 1431 1432 sal_Bool ImpGraphic::ImplSwapOut() 1433 { 1434 sal_Bool bRet = sal_False; 1435 1436 if( !ImplIsSwapOut() ) 1437 { 1438 if( !maDocFileURLStr.Len() ) 1439 { 1440 ::utl::TempFile aTempFile; 1441 const INetURLObject aTmpURL( aTempFile.GetURL() ); 1442 1443 if( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ).getLength() ) 1444 { 1445 SvStream* pOStm = ::utl::UcbStreamHelper::CreateStream( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1446 1447 if( pOStm ) 1448 { 1449 pOStm->SetVersion( SOFFICE_FILEFORMAT_50 ); 1450 pOStm->SetCompressMode( COMPRESSMODE_NATIVE ); 1451 1452 if( ( bRet = ImplSwapOut( pOStm ) ) == sal_True ) 1453 { 1454 mpSwapFile = new ImpSwapFile; 1455 mpSwapFile->nRefCount = 1; 1456 mpSwapFile->aSwapURL = aTmpURL; 1457 } 1458 else 1459 { 1460 delete pOStm, pOStm = NULL; 1461 1462 try 1463 { 1464 ::ucbhelper::Content aCnt( aTmpURL.GetMainURL( INetURLObject::NO_DECODE ), 1465 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1466 1467 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1468 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1469 } 1470 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1471 { 1472 } 1473 catch( const ::com::sun::star::uno::RuntimeException& ) 1474 { 1475 } 1476 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1477 { 1478 } 1479 catch( const ::com::sun::star::uno::Exception& ) 1480 { 1481 } 1482 } 1483 1484 delete pOStm; 1485 } 1486 } 1487 } 1488 else 1489 { 1490 ImplClearGraphics( sal_True ); 1491 bRet = mbSwapOut = sal_True; 1492 } 1493 } 1494 1495 return bRet; 1496 } 1497 1498 // ------------------------------------------------------------------------ 1499 1500 sal_Bool ImpGraphic::ImplSwapOut( SvStream* pOStm ) 1501 { 1502 sal_Bool bRet = sal_False; 1503 1504 if( pOStm ) 1505 { 1506 pOStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); 1507 1508 if( !pOStm->GetError() && ImplWriteEmbedded( *pOStm ) ) 1509 { 1510 pOStm->Flush(); 1511 1512 if( !pOStm->GetError() ) 1513 { 1514 ImplClearGraphics( sal_True ); 1515 bRet = mbSwapOut = sal_True; 1516 } 1517 } 1518 } 1519 else 1520 { 1521 ImplClearGraphics( sal_True ); 1522 bRet = mbSwapOut = sal_True; 1523 } 1524 1525 return bRet; 1526 } 1527 1528 // ------------------------------------------------------------------------ 1529 1530 sal_Bool ImpGraphic::ImplSwapIn() 1531 { 1532 sal_Bool bRet = sal_False; 1533 1534 if( ImplIsSwapOut() ) 1535 { 1536 String aSwapURL; 1537 1538 if( mpSwapFile ) 1539 aSwapURL = mpSwapFile->aSwapURL.GetMainURL( INetURLObject::NO_DECODE ); 1540 else 1541 aSwapURL = maDocFileURLStr; 1542 1543 if( aSwapURL.Len() ) 1544 { 1545 SvStream* pIStm = ::utl::UcbStreamHelper::CreateStream( aSwapURL, STREAM_READWRITE | STREAM_SHARE_DENYWRITE ); 1546 1547 if( pIStm ) 1548 { 1549 pIStm->SetVersion( SOFFICE_FILEFORMAT_50 ); 1550 pIStm->SetCompressMode( COMPRESSMODE_NATIVE ); 1551 1552 if( !mpSwapFile ) 1553 pIStm->Seek( mnDocFilePos ); 1554 1555 bRet = ImplSwapIn( pIStm ); 1556 delete pIStm; 1557 1558 if( mpSwapFile ) 1559 { 1560 if( mpSwapFile->nRefCount > 1 ) 1561 mpSwapFile->nRefCount--; 1562 else 1563 { 1564 try 1565 { 1566 ::ucbhelper::Content aCnt( aSwapURL, 1567 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 1568 1569 aCnt.executeCommand( ::rtl::OUString::createFromAscii( "delete" ), 1570 ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); 1571 } 1572 catch( const ::com::sun::star::ucb::ContentCreationException& ) 1573 { 1574 } 1575 catch( const ::com::sun::star::uno::RuntimeException& ) 1576 { 1577 } 1578 catch( const ::com::sun::star::ucb::CommandAbortedException& ) 1579 { 1580 } 1581 catch( const ::com::sun::star::uno::Exception& ) 1582 { 1583 } 1584 1585 delete mpSwapFile; 1586 } 1587 1588 mpSwapFile = NULL; 1589 } 1590 } 1591 } 1592 } 1593 1594 return bRet; 1595 } 1596 1597 // ------------------------------------------------------------------------ 1598 1599 sal_Bool ImpGraphic::ImplSwapIn( SvStream* pIStm ) 1600 { 1601 sal_Bool bRet = sal_False; 1602 1603 if( pIStm ) 1604 { 1605 pIStm->SetBufferSize( GRAPHIC_STREAMBUFSIZE ); 1606 1607 if( !pIStm->GetError() ) 1608 { 1609 mbSwapUnderway = sal_True; 1610 bRet = ImplReadEmbedded( *pIStm ); 1611 mbSwapUnderway = sal_False; 1612 1613 if( !bRet ) 1614 ImplClear(); 1615 else 1616 mbSwapOut = sal_False; 1617 } 1618 } 1619 1620 return bRet; 1621 } 1622 1623 // ------------------------------------------------------------------------ 1624 1625 sal_Bool ImpGraphic::ImplIsSwapOut() const 1626 { 1627 return mbSwapOut; 1628 } 1629 1630 // ------------------------------------------------------------------------ 1631 1632 void ImpGraphic::ImplSetLink( const GfxLink& rGfxLink ) 1633 { 1634 delete mpGfxLink; 1635 mpGfxLink = new GfxLink( rGfxLink ); 1636 1637 if( mpGfxLink->IsNative() ) 1638 mpGfxLink->SwapOut(); 1639 } 1640 1641 // ------------------------------------------------------------------------ 1642 1643 GfxLink ImpGraphic::ImplGetLink() 1644 { 1645 return( mpGfxLink ? *mpGfxLink : GfxLink() ); 1646 } 1647 1648 // ------------------------------------------------------------------------ 1649 1650 sal_Bool ImpGraphic::ImplIsLink() const 1651 { 1652 return ( mpGfxLink != NULL ) ? sal_True : sal_False; 1653 } 1654 1655 // ------------------------------------------------------------------------ 1656 1657 sal_uLong ImpGraphic::ImplGetChecksum() const 1658 { 1659 sal_uLong nRet = 0; 1660 1661 if( ImplIsSupportedGraphic() && !ImplIsSwapOut() ) 1662 { 1663 switch( meType ) 1664 { 1665 case( GRAPHIC_DEFAULT ): 1666 break; 1667 1668 case( GRAPHIC_BITMAP ): 1669 { 1670 if(maSvgData.get() && maEx.IsEmpty()) 1671 { 1672 // use maEx as local buffer for rendered svg 1673 const_cast< ImpGraphic* >(this)->maEx = maSvgData->getReplacement(); 1674 } 1675 1676 if( mpAnimation ) 1677 { 1678 nRet = mpAnimation->GetChecksum(); 1679 } 1680 else 1681 { 1682 nRet = maEx.GetChecksum(); 1683 } 1684 } 1685 break; 1686 1687 default: 1688 nRet = maMetaFile.GetChecksum(); 1689 break; 1690 } 1691 } 1692 1693 return nRet; 1694 } 1695 1696 // ------------------------------------------------------------------------ 1697 1698 sal_Bool ImpGraphic::ImplExportNative( SvStream& rOStm ) const 1699 { 1700 sal_Bool bResult = sal_False; 1701 1702 if( !rOStm.GetError() ) 1703 { 1704 if( !ImplIsSwapOut() ) 1705 { 1706 if( mpGfxLink && mpGfxLink->IsNative() ) 1707 bResult = mpGfxLink->ExportNative( rOStm ); 1708 else 1709 { 1710 rOStm << *this; 1711 bResult = ( rOStm.GetError() == ERRCODE_NONE ); 1712 } 1713 } 1714 else 1715 rOStm.SetError( SVSTREAM_GENERALERROR ); 1716 } 1717 1718 return bResult; 1719 } 1720 1721 // ------------------------------------------------------------------------ 1722 1723 const SvgDataPtr& ImpGraphic::getSvgData() const 1724 { 1725 return maSvgData; 1726 } 1727 1728 // ------------------------------------------------------------------------ 1729 1730 SvStream& operator>>( SvStream& rIStm, ImpGraphic& rImpGraphic ) 1731 { 1732 if( !rIStm.GetError() ) 1733 { 1734 const sal_uLong nStmPos1 = rIStm.Tell(); 1735 sal_uInt32 nTmp; 1736 1737 if ( !rImpGraphic.mbSwapUnderway ) 1738 rImpGraphic.ImplClear(); 1739 1740 // read Id 1741 rIStm >> nTmp; 1742 1743 // if there is no more data, avoid further expensive 1744 // reading which will create VDevs and other stuff, just to 1745 // read nothing. CAUTION: Eof is only true AFTER reading another 1746 // byte, a speciality of SvMemoryStream (!) 1747 if(!rIStm.GetError() && !rIStm.IsEof()) 1748 { 1749 if( NATIVE_FORMAT_50 == nTmp ) 1750 { 1751 Graphic aGraphic; 1752 GfxLink aLink; 1753 VersionCompat* pCompat; 1754 1755 // read compat info 1756 pCompat = new VersionCompat( rIStm, STREAM_READ ); 1757 delete pCompat; 1758 1759 rIStm >> aLink; 1760 1761 // set dummy link to avoid creation of additional link after filtering; 1762 // we set a default link to avoid unnecessary swapping of native data 1763 aGraphic.SetLink( GfxLink() ); 1764 1765 if( !rIStm.GetError() && aLink.LoadNative( aGraphic ) ) 1766 { 1767 // set link only, if no other link was set 1768 const sal_Bool bSetLink = ( rImpGraphic.mpGfxLink == NULL ); 1769 1770 // assign graphic 1771 rImpGraphic = *aGraphic.ImplGetImpGraphic(); 1772 1773 if( aLink.IsPrefMapModeValid() ) 1774 rImpGraphic.ImplSetPrefMapMode( aLink.GetPrefMapMode() ); 1775 1776 if( aLink.IsPrefSizeValid() ) 1777 rImpGraphic.ImplSetPrefSize( aLink.GetPrefSize() ); 1778 1779 if( bSetLink ) 1780 rImpGraphic.ImplSetLink( aLink ); 1781 } 1782 else 1783 { 1784 rIStm.Seek( nStmPos1 ); 1785 rIStm.SetError( ERRCODE_IO_WRONGFORMAT ); 1786 } 1787 } 1788 else 1789 { 1790 BitmapEx aBmpEx; 1791 const sal_uInt16 nOldFormat = rIStm.GetNumberFormatInt(); 1792 1793 rIStm.SeekRel( -4 ); 1794 rIStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1795 ReadDIBBitmapEx(aBmpEx, rIStm); 1796 1797 if( !rIStm.GetError() ) 1798 { 1799 sal_uInt32 nMagic1(0), nMagic2(0); 1800 sal_uLong nActPos = rIStm.Tell(); 1801 1802 rIStm >> nMagic1 >> nMagic2; 1803 rIStm.Seek( nActPos ); 1804 1805 rImpGraphic = ImpGraphic( aBmpEx ); 1806 1807 if( !rIStm.GetError() && ( 0x5344414e == nMagic1 ) && ( 0x494d4931 == nMagic2 ) ) 1808 { 1809 delete rImpGraphic.mpAnimation; 1810 rImpGraphic.mpAnimation = new Animation; 1811 rIStm >> *rImpGraphic.mpAnimation; 1812 1813 // #108077# manually set loaded BmpEx to Animation 1814 // (which skips loading its BmpEx if already done) 1815 rImpGraphic.mpAnimation->SetBitmapEx(aBmpEx); 1816 } 1817 else 1818 rIStm.ResetError(); 1819 } 1820 else 1821 { 1822 GDIMetaFile aMtf; 1823 1824 rIStm.Seek( nStmPos1 ); 1825 rIStm.ResetError(); 1826 rIStm >> aMtf; 1827 1828 if( !rIStm.GetError() ) 1829 { 1830 rImpGraphic = aMtf; 1831 } 1832 else 1833 { 1834 // try to stream in Svg defining data (length, byte array and evtl. path) 1835 // See below (operator<<) for more information 1836 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0')); 1837 sal_uInt32 nMagic; 1838 rIStm.Seek(nStmPos1); 1839 rIStm.ResetError(); 1840 rIStm >> nMagic; 1841 1842 if(nSvgMagic == nMagic) 1843 { 1844 sal_uInt32 mnSvgDataArrayLength(0); 1845 rIStm >> mnSvgDataArrayLength; 1846 1847 if(mnSvgDataArrayLength) 1848 { 1849 SvgDataArray aNewData(new sal_uInt8[mnSvgDataArrayLength]); 1850 UniString aPath; 1851 1852 rIStm.Read(aNewData.get(), mnSvgDataArrayLength); 1853 rIStm.ReadByteString(aPath); 1854 1855 if(!rIStm.GetError()) 1856 { 1857 SvgDataPtr aSvgDataPtr( 1858 new SvgData( 1859 aNewData, 1860 mnSvgDataArrayLength, 1861 rtl::OUString(aPath))); 1862 1863 rImpGraphic = aSvgDataPtr; 1864 } 1865 } 1866 } 1867 1868 rIStm.Seek(nStmPos1); 1869 } 1870 } 1871 1872 rIStm.SetNumberFormatInt( nOldFormat ); 1873 } 1874 } 1875 } 1876 1877 return rIStm; 1878 } 1879 1880 // ------------------------------------------------------------------------ 1881 1882 SvStream& operator<<( SvStream& rOStm, const ImpGraphic& rImpGraphic ) 1883 { 1884 if( !rOStm.GetError() ) 1885 { 1886 if( !rImpGraphic.ImplIsSwapOut() ) 1887 { 1888 if( ( rOStm.GetVersion() >= SOFFICE_FILEFORMAT_50 ) && 1889 ( rOStm.GetCompressMode() & COMPRESSMODE_NATIVE ) && 1890 rImpGraphic.mpGfxLink && rImpGraphic.mpGfxLink->IsNative() ) 1891 { 1892 VersionCompat* pCompat; 1893 1894 // native format 1895 rOStm << NATIVE_FORMAT_50; 1896 1897 // write compat info 1898 pCompat = new VersionCompat( rOStm, STREAM_WRITE, 1 ); 1899 delete pCompat; 1900 1901 rImpGraphic.mpGfxLink->SetPrefMapMode( rImpGraphic.ImplGetPrefMapMode() ); 1902 rImpGraphic.mpGfxLink->SetPrefSize( rImpGraphic.ImplGetPrefSize() ); 1903 rOStm << *rImpGraphic.mpGfxLink; 1904 } 1905 else 1906 { 1907 // own format 1908 const sal_uInt16 nOldFormat = rOStm.GetNumberFormatInt(); 1909 rOStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); 1910 1911 switch( rImpGraphic.ImplGetType() ) 1912 { 1913 case( GRAPHIC_NONE ): 1914 case( GRAPHIC_DEFAULT ): 1915 break; 1916 1917 case GRAPHIC_BITMAP: 1918 { 1919 if(rImpGraphic.getSvgData().get()) 1920 { 1921 // stream out Svg defining data (length, byte array and evtl. path) 1922 // this is used e.g. in swapping out graphic data and in transporting it over UNO API 1923 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be 1924 // no problem to extend it; only used at runtime 1925 const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0')); 1926 1927 rOStm << nSvgMagic; 1928 rOStm << rImpGraphic.getSvgData()->getSvgDataArrayLength(); 1929 rOStm.Write(rImpGraphic.getSvgData()->getSvgDataArray().get(), rImpGraphic.getSvgData()->getSvgDataArrayLength()); 1930 rOStm.WriteByteString(rImpGraphic.getSvgData()->getPath()); 1931 } 1932 else if( rImpGraphic.ImplIsAnimated()) 1933 { 1934 rOStm << *rImpGraphic.mpAnimation; 1935 } 1936 else 1937 { 1938 WriteDIBBitmapEx(rImpGraphic.maEx, rOStm); 1939 } 1940 } 1941 break; 1942 1943 default: 1944 { 1945 if( rImpGraphic.ImplIsSupportedGraphic() ) 1946 rOStm << rImpGraphic.maMetaFile; 1947 } 1948 break; 1949 } 1950 1951 rOStm.SetNumberFormatInt( nOldFormat ); 1952 } 1953 } 1954 else 1955 rOStm.SetError( SVSTREAM_GENERALERROR ); 1956 } 1957 1958 return rOStm; 1959 } 1960