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