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