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