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