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