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