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