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