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