xref: /aoo42x/main/vcl/source/gdi/impgraph.cxx (revision ff494be3)
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