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