android: Reuse launcher icon in activities
[LibreOffice.git] / vcl / source / gdi / impgraph.cxx
blobc4a5a1ca11b5f4e170e0671619d6d5ea37cee579
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <comphelper/fileformat.h>
24 #include <o3tl/make_shared.hxx>
25 #include <tools/fract.hxx>
26 #include <tools/vcompat.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/stream.hxx>
29 #include <unotools/ucbhelper.hxx>
30 #include <unotools/ucbstreamhelper.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <utility>
33 #include <vcl/filter/SvmReader.hxx>
34 #include <vcl/filter/SvmWriter.hxx>
35 #include <vcl/outdev.hxx>
36 #include <vcl/graphicfilter.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/gfxlink.hxx>
39 #include <vcl/cvtgrf.hxx>
40 #include <vcl/graph.hxx>
41 #include <vcl/metaact.hxx>
42 #include <impgraph.hxx>
43 #include <com/sun/star/graphic/XPrimitive2D.hpp>
44 #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
45 #include <vcl/dibtools.hxx>
46 #include <map>
47 #include <memory>
48 #include <vcl/gdimetafiletools.hxx>
49 #include <vcl/TypeSerializer.hxx>
50 #include <vcl/pdfread.hxx>
51 #include <graphic/VectorGraphicLoader.hxx>
53 #define GRAPHIC_MTFTOBMP_MAXEXT 2048
54 #define GRAPHIC_STREAMBUFSIZE 8192UL
56 #define SWAP_FORMAT_ID COMPAT_FORMAT( 'S', 'W', 'A', 'P' )
58 using namespace com::sun::star;
61 class ImpSwapFile
63 private:
64 utl::TempFileFast maTempFile;
65 OUString maOriginURL;
67 public:
68 ImpSwapFile(OUString aOriginURL)
69 : maOriginURL(std::move(aOriginURL))
73 SvStream* getStream() { return maTempFile.GetStream(StreamMode::READWRITE); }
74 OUString const & getOriginURL() const { return maOriginURL; }
77 SvStream* ImpGraphic::getSwapFileStream() const
79 if (mpSwapFile)
80 return mpSwapFile->getStream();
81 return nullptr;
84 ImpGraphic::ImpGraphic() :
85 meType ( GraphicType::NONE ),
86 mnSizeBytes ( 0 ),
87 mbSwapOut ( false ),
88 mbDummyContext ( false ),
89 maLastUsed (std::chrono::high_resolution_clock::now()),
90 mbPrepared ( false )
94 ImpGraphic::ImpGraphic(const ImpGraphic& rImpGraphic)
95 : maMetaFile(rImpGraphic.maMetaFile)
96 , maBitmapEx(rImpGraphic.maBitmapEx)
97 , maSwapInfo(rImpGraphic.maSwapInfo)
98 , mpContext(rImpGraphic.mpContext)
99 , mpSwapFile(rImpGraphic.mpSwapFile)
100 , mpGfxLink(rImpGraphic.mpGfxLink)
101 , meType(rImpGraphic.meType)
102 , mnSizeBytes(rImpGraphic.mnSizeBytes)
103 , mbSwapOut(rImpGraphic.mbSwapOut)
104 , mbDummyContext(rImpGraphic.mbDummyContext)
105 , maVectorGraphicData(rImpGraphic.maVectorGraphicData)
106 , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink)
107 , maLastUsed (std::chrono::high_resolution_clock::now())
108 , mbPrepared (rImpGraphic.mbPrepared)
110 if( rImpGraphic.mpAnimation )
112 mpAnimation = std::make_unique<Animation>( *rImpGraphic.mpAnimation );
113 maBitmapEx = mpAnimation->GetBitmapEx();
117 ImpGraphic::ImpGraphic(ImpGraphic&& rImpGraphic) noexcept
118 : maMetaFile(std::move(rImpGraphic.maMetaFile))
119 , maBitmapEx(std::move(rImpGraphic.maBitmapEx))
120 , maSwapInfo(std::move(rImpGraphic.maSwapInfo))
121 , mpAnimation(std::move(rImpGraphic.mpAnimation))
122 , mpContext(std::move(rImpGraphic.mpContext))
123 , mpSwapFile(std::move(rImpGraphic.mpSwapFile))
124 , mpGfxLink(std::move(rImpGraphic.mpGfxLink))
125 , meType(rImpGraphic.meType)
126 , mnSizeBytes(rImpGraphic.mnSizeBytes)
127 , mbSwapOut(rImpGraphic.mbSwapOut)
128 , mbDummyContext(rImpGraphic.mbDummyContext)
129 , maVectorGraphicData(std::move(rImpGraphic.maVectorGraphicData))
130 , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink)
131 , maLastUsed (std::chrono::high_resolution_clock::now())
132 , mbPrepared (rImpGraphic.mbPrepared)
134 rImpGraphic.clear();
135 rImpGraphic.mbDummyContext = false;
138 ImpGraphic::ImpGraphic(std::shared_ptr<GfxLink> xGfxLink, sal_Int32 nPageIndex)
139 : mpGfxLink(std::move(xGfxLink))
140 , meType(GraphicType::Bitmap)
141 , mnSizeBytes(0)
142 , mbSwapOut(true)
143 , mbDummyContext(false)
144 , maLastUsed (std::chrono::high_resolution_clock::now())
145 , mbPrepared (false)
147 maSwapInfo.mbIsTransparent = true;
148 maSwapInfo.mbIsAlpha = true;
149 maSwapInfo.mbIsEPS = false;
150 maSwapInfo.mbIsAnimated = false;
151 maSwapInfo.mnAnimationLoopCount = 0;
152 maSwapInfo.mnPageIndex = nPageIndex;
155 ImpGraphic::ImpGraphic(GraphicExternalLink aGraphicExternalLink) :
156 meType ( GraphicType::Default ),
157 mnSizeBytes ( 0 ),
158 mbSwapOut ( false ),
159 mbDummyContext ( false ),
160 maGraphicExternalLink(std::move(aGraphicExternalLink)),
161 maLastUsed (std::chrono::high_resolution_clock::now()),
162 mbPrepared (false)
166 ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) :
167 maBitmapEx ( rBitmapEx ),
168 meType ( !rBitmapEx.IsEmpty() ? GraphicType::Bitmap : GraphicType::NONE ),
169 mnSizeBytes ( 0 ),
170 mbSwapOut ( false ),
171 mbDummyContext ( false ),
172 maLastUsed (std::chrono::high_resolution_clock::now()),
173 mbPrepared (false)
177 ImpGraphic::ImpGraphic(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr)
178 : meType( rVectorGraphicDataPtr ? GraphicType::Bitmap : GraphicType::NONE ),
179 mnSizeBytes( 0 ),
180 mbSwapOut( false ),
181 mbDummyContext ( false ),
182 maVectorGraphicData(rVectorGraphicDataPtr),
183 maLastUsed (std::chrono::high_resolution_clock::now()),
184 mbPrepared (false)
188 ImpGraphic::ImpGraphic( const Animation& rAnimation ) :
189 maBitmapEx ( rAnimation.GetBitmapEx() ),
190 mpAnimation ( std::make_unique<Animation>( rAnimation ) ),
191 meType ( GraphicType::Bitmap ),
192 mnSizeBytes ( 0 ),
193 mbSwapOut ( false ),
194 mbDummyContext ( false ),
195 maLastUsed (std::chrono::high_resolution_clock::now()),
196 mbPrepared (false)
200 ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) :
201 maMetaFile ( rMtf ),
202 meType ( GraphicType::GdiMetafile ),
203 mnSizeBytes ( 0 ),
204 mbSwapOut ( false ),
205 mbDummyContext ( false ),
206 maLastUsed (std::chrono::high_resolution_clock::now()),
207 mbPrepared (false)
211 ImpGraphic::~ImpGraphic()
213 vcl::graphic::Manager::get().unregisterGraphic(this);
216 ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic )
218 if( &rImpGraphic != this )
220 sal_Int64 aOldSizeBytes = mnSizeBytes;
222 maMetaFile = rImpGraphic.maMetaFile;
223 meType = rImpGraphic.meType;
224 mnSizeBytes = rImpGraphic.mnSizeBytes;
226 maSwapInfo = rImpGraphic.maSwapInfo;
227 mpContext = rImpGraphic.mpContext;
228 mbDummyContext = rImpGraphic.mbDummyContext;
229 maGraphicExternalLink = rImpGraphic.maGraphicExternalLink;
231 mpAnimation.reset();
233 if ( rImpGraphic.mpAnimation )
235 mpAnimation = std::make_unique<Animation>( *rImpGraphic.mpAnimation );
236 maBitmapEx = mpAnimation->GetBitmapEx();
238 else
240 maBitmapEx = rImpGraphic.maBitmapEx;
243 mbSwapOut = rImpGraphic.mbSwapOut;
244 mpSwapFile = rImpGraphic.mpSwapFile;
245 mbPrepared = rImpGraphic.mbPrepared;
247 mpGfxLink = rImpGraphic.mpGfxLink;
249 maVectorGraphicData = rImpGraphic.maVectorGraphicData;
250 maLastUsed = std::chrono::high_resolution_clock::now();
252 vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes);
255 return *this;
258 ImpGraphic& ImpGraphic::operator=(ImpGraphic&& rImpGraphic)
260 sal_Int64 aOldSizeBytes = mnSizeBytes;
262 maMetaFile = std::move(rImpGraphic.maMetaFile);
263 meType = rImpGraphic.meType;
264 mnSizeBytes = rImpGraphic.mnSizeBytes;
265 maSwapInfo = std::move(rImpGraphic.maSwapInfo);
266 mpContext = std::move(rImpGraphic.mpContext);
267 mbDummyContext = rImpGraphic.mbDummyContext;
268 mpAnimation = std::move(rImpGraphic.mpAnimation);
269 maBitmapEx = std::move(rImpGraphic.maBitmapEx);
270 mbSwapOut = rImpGraphic.mbSwapOut;
271 mpSwapFile = std::move(rImpGraphic.mpSwapFile);
272 mpGfxLink = std::move(rImpGraphic.mpGfxLink);
273 maVectorGraphicData = std::move(rImpGraphic.maVectorGraphicData);
274 maGraphicExternalLink = rImpGraphic.maGraphicExternalLink;
275 mbPrepared = rImpGraphic.mbPrepared;
277 rImpGraphic.clear();
278 rImpGraphic.mbDummyContext = false;
279 maLastUsed = std::chrono::high_resolution_clock::now();
281 vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes);
283 return *this;
286 bool ImpGraphic::operator==( const ImpGraphic& rOther ) const
288 if( this == &rOther )
289 return true;
291 if (mbPrepared && rOther.mbPrepared)
292 return (*mpGfxLink == *rOther.mpGfxLink);
294 if (!isAvailable() || !rOther.isAvailable())
295 return false;
297 if ( meType != rOther.meType )
298 return false;
300 bool bRet = false;
301 switch( meType )
303 case GraphicType::NONE:
304 case GraphicType::Default:
305 return true;
307 case GraphicType::GdiMetafile:
308 return ( rOther.maMetaFile == maMetaFile );
310 case GraphicType::Bitmap:
312 if(maVectorGraphicData)
314 if(maVectorGraphicData == rOther.maVectorGraphicData)
316 // equal instances
317 bRet = true;
319 else if(rOther.maVectorGraphicData)
321 // equal content
322 bRet = (*maVectorGraphicData) == (*rOther.maVectorGraphicData);
325 else if( mpAnimation )
327 if( rOther.mpAnimation && ( *rOther.mpAnimation == *mpAnimation ) )
328 bRet = true;
330 else if( !rOther.mpAnimation && ( rOther.maBitmapEx == maBitmapEx ) )
332 bRet = true;
335 break;
338 return bRet;
341 const std::shared_ptr<VectorGraphicData>& ImpGraphic::getVectorGraphicData() const
343 ensureAvailable();
345 return maVectorGraphicData;
348 void ImpGraphic::createSwapInfo()
350 if (isSwappedOut())
351 return;
353 if (!maBitmapEx.IsEmpty())
354 maSwapInfo.maSizePixel = maBitmapEx.GetSizePixel();
355 else
356 maSwapInfo.maSizePixel = Size();
358 maSwapInfo.maPrefMapMode = getPrefMapMode();
359 maSwapInfo.maPrefSize = getPrefSize();
360 maSwapInfo.mbIsAnimated = isAnimated();
361 maSwapInfo.mbIsEPS = isEPS();
362 maSwapInfo.mbIsTransparent = isTransparent();
363 maSwapInfo.mbIsAlpha = isAlpha();
364 maSwapInfo.mnAnimationLoopCount = getAnimationLoopCount();
365 maSwapInfo.mnPageIndex = getPageNumber();
368 void ImpGraphic::clearGraphics()
370 maBitmapEx.Clear();
371 maMetaFile.Clear();
372 mpAnimation.reset();
373 maVectorGraphicData.reset();
376 void ImpGraphic::setPrepared(bool bAnimated, const Size* pSizeHint)
378 mbPrepared = true;
379 mbSwapOut = true;
380 meType = GraphicType::Bitmap;
382 SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(mpGfxLink->GetData()), mpGfxLink->GetDataSize(), StreamMode::READ | StreamMode::WRITE);
384 if (pSizeHint)
386 maSwapInfo.maPrefSize = *pSizeHint;
387 maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM);
390 GraphicDescriptor aDescriptor(aMemoryStream, nullptr);
391 if (aDescriptor.Detect(true))
393 if (!pSizeHint)
395 // If we have logic size, work with that, as later pixel -> logic
396 // conversion will work with the output device DPI, not the graphic
397 // DPI.
398 Size aLogSize = aDescriptor.GetSize_100TH_MM();
399 if (aDescriptor.GetPreferredLogSize() && aDescriptor.GetPreferredMapMode())
401 maSwapInfo.maPrefSize = *aDescriptor.GetPreferredLogSize();
402 maSwapInfo.maPrefMapMode = *aDescriptor.GetPreferredMapMode();
404 else if (aLogSize.getWidth() && aLogSize.getHeight())
406 maSwapInfo.maPrefSize = aLogSize;
407 maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM);
409 else
411 maSwapInfo.maPrefSize = aDescriptor.GetSizePixel();
412 maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel);
416 maSwapInfo.maSizePixel = aDescriptor.GetSizePixel();
417 maSwapInfo.mbIsTransparent = aDescriptor.IsTransparent();
418 maSwapInfo.mbIsAlpha = aDescriptor.IsAlpha();
419 } else {
420 maSwapInfo.mbIsTransparent = false;
421 maSwapInfo.mbIsAlpha = false;
424 maSwapInfo.mnAnimationLoopCount = 0;
425 maSwapInfo.mbIsEPS = false;
426 maSwapInfo.mbIsAnimated = bAnimated;
428 if (maVectorGraphicData)
429 maSwapInfo.mnPageIndex = maVectorGraphicData->getPageIndex();
432 void ImpGraphic::clear()
434 mpSwapFile.reset();
435 mbSwapOut = false;
436 mbPrepared = false;
438 // cleanup
439 clearGraphics();
440 meType = GraphicType::NONE;
441 sal_Int64 nOldSize = mnSizeBytes;
442 mnSizeBytes = 0;
443 vcl::graphic::Manager::get().changeExisting(this, nOldSize);
444 maGraphicExternalLink.msURL.clear();
447 void ImpGraphic::setDefaultType()
449 clear();
450 meType = GraphicType::Default;
453 bool ImpGraphic::isSupportedGraphic() const
455 return( meType != GraphicType::NONE );
458 bool ImpGraphic::isTransparent() const
460 bool bRet(true);
462 if (mbSwapOut)
464 bRet = maSwapInfo.mbIsTransparent;
466 else if (meType == GraphicType::Bitmap && !maVectorGraphicData)
468 bRet = mpAnimation ? mpAnimation->IsTransparent() : maBitmapEx.IsAlpha();
471 return bRet;
474 bool ImpGraphic::isAlpha() const
476 bool bRet(false);
478 if (mbSwapOut)
480 bRet = maSwapInfo.mbIsAlpha;
482 else if (maVectorGraphicData)
484 bRet = true;
486 else if (meType == GraphicType::Bitmap)
488 bRet = (nullptr == mpAnimation && maBitmapEx.IsAlpha());
491 return bRet;
494 bool ImpGraphic::isAnimated() const
496 return mbSwapOut ? maSwapInfo.mbIsAnimated : mpAnimation != nullptr;
499 bool ImpGraphic::isEPS() const
501 if (mbSwapOut)
502 return maSwapInfo.mbIsEPS;
504 return( ( meType == GraphicType::GdiMetafile ) &&
505 ( maMetaFile.GetActionSize() > 0 ) &&
506 ( maMetaFile.GetAction( 0 )->GetType() == MetaActionType::EPS ) );
509 bool ImpGraphic::isAvailable() const
511 return !mbPrepared && !mbSwapOut;
514 bool ImpGraphic::makeAvailable()
516 return ensureAvailable();
519 BitmapEx ImpGraphic::getVectorGraphicReplacement() const
521 BitmapEx aRet = maVectorGraphicData->getReplacement();
523 if (maExPrefSize.getWidth() && maExPrefSize.getHeight())
525 aRet.SetPrefSize(maExPrefSize);
528 return aRet;
531 Bitmap ImpGraphic::getBitmap(const GraphicConversionParameters& rParameters) const
533 Bitmap aRetBmp;
535 ensureAvailable();
537 if( meType == GraphicType::Bitmap )
539 if(maVectorGraphicData && maBitmapEx.IsEmpty())
541 // use maBitmapEx as local buffer for rendered svg
542 const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement();
545 const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx );
547 aRetBmp = rRetBmpEx.GetBitmap( COL_WHITE );
549 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
550 aRetBmp.Scale(rParameters.getSizePixel());
552 else if( ( meType != GraphicType::Default ) && isSupportedGraphic() )
554 if(maBitmapEx.IsEmpty())
556 // calculate size
557 ScopedVclPtrInstance< VirtualDevice > aVDev;
558 Size aDrawSize(aVDev->LogicToPixel(maMetaFile.GetPrefSize(), maMetaFile.GetPrefMapMode()));
560 if(rParameters.getSizePixel().Width() && rParameters.getSizePixel().Height())
562 // apply given size if exists
563 aDrawSize = rParameters.getSizePixel();
566 if(aDrawSize.Width() && aDrawSize.Height() && !rParameters.getUnlimitedSize()
567 && (aDrawSize.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aDrawSize.Height() > GRAPHIC_MTFTOBMP_MAXEXT))
569 // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT
570 double fWH(static_cast<double>(aDrawSize.Width()) / static_cast<double>(aDrawSize.Height()));
572 if(fWH <= 1.0)
574 aDrawSize.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT * fWH));
575 aDrawSize.setHeight(GRAPHIC_MTFTOBMP_MAXEXT);
577 else
579 aDrawSize.setWidth(GRAPHIC_MTFTOBMP_MAXEXT);
580 aDrawSize.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT / fWH));
584 // calculate pixel size. Normally, it's the same as aDrawSize, but may
585 // need to be extended when hairlines are on the right or bottom edge
586 Size aPixelSize(aDrawSize);
588 if(GraphicType::GdiMetafile == getType())
590 // tdf#126319 Removed correction based on hairline-at-the-extremes of
591 // the metafile. The task shows that this is no longer sufficient since
592 // less hairlines get used in general - what is good, but breaks that
593 // old fix. Anyways, hairlines are a left-over from non-AA times
594 // when it was not possible to paint lines taller than one pixel.
595 // This might need to be corrected further using primitives and
596 // the possibility to get better-quality ranges for correction. For
597 // now, always add that one pixel.
598 aPixelSize.setWidth(aPixelSize.getWidth() + 1);
599 aPixelSize.setHeight(aPixelSize.getHeight() + 1);
602 if(aVDev->SetOutputSizePixel(aPixelSize))
604 if(rParameters.getAntiAliase())
606 aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::Enable);
609 if(rParameters.getSnapHorVerLines())
611 aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::PixelSnapHairline);
614 draw(*aVDev, Point(), aDrawSize);
616 // use maBitmapEx as local buffer for rendered metafile
617 const_cast< ImpGraphic* >(this)->maBitmapEx = aVDev->GetBitmapEx( Point(), aVDev->GetOutputSizePixel() );
621 aRetBmp = maBitmapEx.GetBitmap();
624 if( !aRetBmp.IsEmpty() )
626 aRetBmp.SetPrefMapMode(getPrefMapMode());
627 aRetBmp.SetPrefSize(getPrefSize());
630 return aRetBmp;
633 BitmapEx ImpGraphic::getBitmapEx(const GraphicConversionParameters& rParameters) const
635 BitmapEx aRetBmpEx;
637 ensureAvailable();
639 if( meType == GraphicType::Bitmap )
641 if(maVectorGraphicData && maBitmapEx.IsEmpty())
643 // use maBitmapEx as local buffer for rendered svg
644 const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement();
647 aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx );
649 if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height())
651 aRetBmpEx.Scale(
652 rParameters.getSizePixel(),
653 BmpScaleFlag::Fast);
656 else if( ( meType != GraphicType::Default ) && isSupportedGraphic() )
658 if(maBitmapEx.IsEmpty())
660 const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) );
662 // use maBitmapEx as local buffer for rendered metafile
663 const_cast< ImpGraphic* >(this)->maBitmapEx = BitmapEx(getBitmap(rParameters), aMonoMask.getBitmap(rParameters));
666 aRetBmpEx = maBitmapEx;
669 return aRetBmpEx;
672 Animation ImpGraphic::getAnimation() const
674 Animation aAnimation;
676 ensureAvailable();
677 if( mpAnimation )
678 aAnimation = *mpAnimation;
680 return aAnimation;
683 const BitmapEx& ImpGraphic::getBitmapExRef() const
685 ensureAvailable();
686 return maBitmapEx;
689 const GDIMetaFile& ImpGraphic::getGDIMetaFile() const
691 ensureAvailable();
692 if (!maMetaFile.GetActionSize()
693 && maVectorGraphicData
694 && (VectorGraphicDataType::Emf == maVectorGraphicData->getType()
695 || VectorGraphicDataType::Wmf == maVectorGraphicData->getType()))
697 // If we have a Emf/Wmf VectorGraphic object, we
698 // need a way to get the Metafile data out of the primitive
699 // representation. Use a strict virtual hook (MetafileAccessor)
700 // to access the MetafilePrimitive2D directly. Also see comments in
701 // XEmfParser about this.
702 const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > aSequence(maVectorGraphicData->getPrimitive2DSequence());
704 if (1 == aSequence.size())
706 // try to cast to MetafileAccessor implementation
707 const css::uno::Reference< css::graphic::XPrimitive2D > xReference(aSequence[0]);
708 auto pUnoPrimitive = static_cast< const drawinglayer::primitive2d::UnoPrimitive2D* >(xReference.get());
709 if (pUnoPrimitive)
711 const MetafileAccessor* pMetafileAccessor = dynamic_cast< const MetafileAccessor* >(pUnoPrimitive->getBasePrimitive2D().get());
713 if (pMetafileAccessor)
715 // it is a MetafileAccessor implementation, get Metafile
716 pMetafileAccessor->accessMetafile(const_cast< ImpGraphic* >(this)->maMetaFile);
722 if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize())
724 // #i119735#
725 // Use the local maMetaFile as container for a metafile-representation
726 // of the bitmap graphic. This will be done only once, thus be buffered.
727 // I checked all usages of maMetaFile, it is only used when type is not
728 // GraphicType::Bitmap. In operator= it will get copied, thus buffering will
729 // survive copying (change this if not wanted)
730 ImpGraphic* pThat = const_cast< ImpGraphic* >(this);
732 if(maVectorGraphicData && maBitmapEx.IsEmpty())
734 // use maBitmapEx as local buffer for rendered svg
735 pThat->maBitmapEx = getVectorGraphicReplacement();
738 // #123983# directly create a metafile with the same PrefSize and PrefMapMode
739 // the bitmap has, this will be an always correct metafile
740 if(maBitmapEx.IsAlpha())
742 pThat->maMetaFile.AddAction(new MetaBmpExScaleAction(Point(), maBitmapEx.GetPrefSize(), maBitmapEx));
744 else
746 pThat->maMetaFile.AddAction(new MetaBmpScaleAction(Point(), maBitmapEx.GetPrefSize(), maBitmapEx.GetBitmap()));
749 pThat->maMetaFile.Stop();
750 pThat->maMetaFile.WindStart();
751 pThat->maMetaFile.SetPrefSize(maBitmapEx.GetPrefSize());
752 pThat->maMetaFile.SetPrefMapMode(maBitmapEx.GetPrefMapMode());
755 return maMetaFile;
758 Size ImpGraphic::getSizePixel() const
760 Size aSize;
762 if (isSwappedOut())
763 aSize = maSwapInfo.maSizePixel;
764 else
765 aSize = getBitmapEx(GraphicConversionParameters()).GetSizePixel();
767 return aSize;
770 Size ImpGraphic::getPrefSize() const
772 Size aSize;
774 if (isSwappedOut())
776 aSize = maSwapInfo.maPrefSize;
778 else
780 switch (meType)
782 case GraphicType::Bitmap:
784 if (maVectorGraphicData && maBitmapEx.IsEmpty())
786 if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight())
788 // svg not yet buffered in maBitmapEx, return size derived from range
789 const basegfx::B2DRange& rRange = maVectorGraphicData->getRange();
791 #ifdef MACOSX
792 // tdf#157680 scale down estimated size of embedded PDF
793 // For some unknown reason, the embedded PDF sizes
794 // are 20x larger than expected. This only occurs on
795 // macOS so possibly there is some special conversion
796 // from MapUnit::MapPoint to MapUnit::MapTwip elsewhere
797 // in the code.
798 if (maVectorGraphicData->getType() == VectorGraphicDataType::Pdf)
799 aSize = Size(basegfx::fround(rRange.getWidth() / 20.0f), basegfx::fround(rRange.getHeight() / 20.0f));
800 else
801 #endif
802 aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight()));
804 else
806 aSize = maExPrefSize;
809 else
811 aSize = maBitmapEx.GetPrefSize();
813 if( !aSize.Width() || !aSize.Height() )
815 aSize = maBitmapEx.GetSizePixel();
819 break;
821 case GraphicType::GdiMetafile:
823 aSize = maMetaFile.GetPrefSize();
825 break;
827 case GraphicType::NONE:
828 case GraphicType::Default:
829 break;
833 return aSize;
836 void ImpGraphic::setValuesForPrefSize(const Size& rPrefSize)
838 switch (meType)
840 case GraphicType::Bitmap:
842 // used when importing a writer FlyFrame with SVG as graphic, added conversion
843 // to allow setting the PrefSize at the BitmapEx to hold it
844 if (maVectorGraphicData && maBitmapEx.IsEmpty())
846 maExPrefSize = rPrefSize;
849 // #108077# Push through pref size to animation object,
850 // will be lost on copy otherwise
851 if (mpAnimation)
853 const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize(rPrefSize);
856 if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight())
858 maBitmapEx.SetPrefSize(rPrefSize);
861 break;
863 case GraphicType::GdiMetafile:
865 if (isSupportedGraphic())
866 maMetaFile.SetPrefSize(rPrefSize);
868 break;
870 case GraphicType::NONE:
871 case GraphicType::Default:
872 break;
876 void ImpGraphic::setPrefSize(const Size& rPrefSize)
878 ensureAvailable();
879 setValuesForPrefSize(rPrefSize);
882 MapMode ImpGraphic::getPrefMapMode() const
884 MapMode aMapMode;
886 if (isSwappedOut())
888 aMapMode = maSwapInfo.maPrefMapMode;
890 else
892 switch (meType)
894 case GraphicType::Bitmap:
896 if (maVectorGraphicData && maBitmapEx.IsEmpty())
898 // svg not yet buffered in maBitmapEx, return default PrefMapMode
899 aMapMode = MapMode(MapUnit::Map100thMM);
901 else
903 const Size aSize(maBitmapEx.GetPrefSize());
905 if (aSize.Width() && aSize.Height())
906 aMapMode = maBitmapEx.GetPrefMapMode();
909 break;
911 case GraphicType::GdiMetafile:
913 return maMetaFile.GetPrefMapMode();
915 break;
917 case GraphicType::NONE:
918 case GraphicType::Default:
919 break;
923 return aMapMode;
926 void ImpGraphic::setValuesForPrefMapMod(const MapMode& rPrefMapMode)
928 switch (meType)
930 case GraphicType::Bitmap:
932 if (maVectorGraphicData)
934 // ignore for Vector Graphic Data. If this is really used (except the grfcache)
935 // it can be extended by using maBitmapEx as buffer for getVectorGraphicReplacement()
937 else
939 // #108077# Push through pref mapmode to animation object,
940 // will be lost on copy otherwise
941 if (mpAnimation)
943 const_cast<BitmapEx&>(mpAnimation->GetBitmapEx()).SetPrefMapMode(rPrefMapMode);
946 maBitmapEx.SetPrefMapMode(rPrefMapMode);
949 break;
951 case GraphicType::GdiMetafile:
953 maMetaFile.SetPrefMapMode(rPrefMapMode);
955 break;
957 case GraphicType::NONE:
958 case GraphicType::Default:
959 break;
963 void ImpGraphic::setPrefMapMode(const MapMode& rPrefMapMode)
965 ensureAvailable();
966 setValuesForPrefMapMod(rPrefMapMode);
969 sal_uLong ImpGraphic::getSizeBytes() const
971 if (mnSizeBytes > 0)
972 return mnSizeBytes;
974 if (mbPrepared)
975 ensureAvailable();
977 switch (meType)
979 case GraphicType::Bitmap:
981 if (maVectorGraphicData)
983 std::pair<VectorGraphicData::State, size_t> aPair(maVectorGraphicData->getSizeBytes());
984 if (VectorGraphicData::State::UNPARSED == aPair.first)
986 return aPair.second; // don't cache it until Vector Graphic Data is parsed
988 mnSizeBytes = aPair.second;
990 else
992 mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maBitmapEx.GetSizeBytes();
995 break;
997 case GraphicType::GdiMetafile:
999 mnSizeBytes = maMetaFile.GetSizeBytes();
1001 break;
1003 case GraphicType::NONE:
1004 case GraphicType::Default:
1005 break;
1008 return mnSizeBytes;
1011 void ImpGraphic::draw(OutputDevice& rOutDev, const Point& rDestPt) const
1013 ensureAvailable();
1015 if (isSwappedOut())
1016 return;
1018 switch (meType)
1020 case GraphicType::Bitmap:
1022 if (maVectorGraphicData && maBitmapEx.IsEmpty())
1024 // use maBitmapEx as local buffer for rendered svg
1025 const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement();
1028 if (mpAnimation)
1030 mpAnimation->Draw(rOutDev, rDestPt);
1032 else
1034 maBitmapEx.Draw(&rOutDev, rDestPt);
1037 break;
1039 case GraphicType::GdiMetafile:
1041 draw(rOutDev, rDestPt, maMetaFile.GetPrefSize());
1043 break;
1045 case GraphicType::Default:
1046 case GraphicType::NONE:
1047 break;
1051 void ImpGraphic::draw(OutputDevice& rOutDev,
1052 const Point& rDestPt, const Size& rDestSize) const
1054 ensureAvailable();
1056 if (isSwappedOut())
1057 return;
1059 switch (meType)
1061 case GraphicType::Bitmap:
1063 if (maVectorGraphicData && maBitmapEx.IsEmpty())
1065 // use maBitmapEx as local buffer for rendered svg
1066 const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement();
1069 if (mpAnimation)
1071 mpAnimation->Draw(rOutDev, rDestPt, rDestSize);
1073 else
1075 maBitmapEx.Draw(&rOutDev, rDestPt, rDestSize);
1078 break;
1080 case GraphicType::GdiMetafile:
1082 const_cast<ImpGraphic*>(this)->maMetaFile.WindStart();
1083 const_cast<ImpGraphic*>(this)->maMetaFile.Play(rOutDev, rDestPt, rDestSize);
1084 const_cast<ImpGraphic*>(this)->maMetaFile.WindStart();
1086 break;
1088 case GraphicType::Default:
1089 case GraphicType::NONE:
1090 break;
1094 void ImpGraphic::startAnimation(OutputDevice& rOutDev, const Point& rDestPt,
1095 const Size& rDestSize, tools::Long nRendererId,
1096 OutputDevice* pFirstFrameOutDev )
1098 ensureAvailable();
1100 if( isSupportedGraphic() && !isSwappedOut() && mpAnimation )
1101 mpAnimation->Start(rOutDev, rDestPt, rDestSize, nRendererId, pFirstFrameOutDev);
1104 void ImpGraphic::stopAnimation( const OutputDevice* pOutDev, tools::Long nRendererId )
1106 ensureAvailable();
1108 if( isSupportedGraphic() && !isSwappedOut() && mpAnimation )
1109 mpAnimation->Stop( pOutDev, nRendererId );
1112 void ImpGraphic::setAnimationNotifyHdl( const Link<Animation*,void>& rLink )
1114 ensureAvailable();
1116 if( mpAnimation )
1117 mpAnimation->SetNotifyHdl( rLink );
1120 Link<Animation*,void> ImpGraphic::getAnimationNotifyHdl() const
1122 Link<Animation*,void> aLink;
1124 ensureAvailable();
1126 if( mpAnimation )
1127 aLink = mpAnimation->GetNotifyHdl();
1129 return aLink;
1132 sal_uInt32 ImpGraphic::getAnimationLoopCount() const
1134 if (mbSwapOut)
1135 return maSwapInfo.mnAnimationLoopCount;
1137 return mpAnimation ? mpAnimation->GetLoopCount() : 0;
1140 void ImpGraphic::setContext( const std::shared_ptr<GraphicReader>& pReader )
1142 mpContext = pReader;
1143 mbDummyContext = false;
1146 bool ImpGraphic::swapInContent(SvStream& rStream)
1148 bool bRet = false;
1150 sal_uInt32 nId;
1151 sal_Int32 nType;
1152 sal_Int32 nLength;
1154 rStream.ReadUInt32(nId);
1156 // check version
1157 if (SWAP_FORMAT_ID != nId)
1159 SAL_WARN("vcl", "Incompatible swap file!");
1160 return false;
1163 rStream.ReadInt32(nType);
1164 rStream.ReadInt32(nLength);
1166 meType = static_cast<GraphicType>(nType);
1168 if (meType == GraphicType::NONE || meType == GraphicType::Default)
1170 return true;
1172 else
1174 bRet = swapInGraphic(rStream);
1177 return bRet;
1180 bool ImpGraphic::swapOutGraphic(SvStream& rStream)
1182 if (rStream.GetError())
1183 return false;
1185 ensureAvailable();
1187 if (isSwappedOut())
1189 rStream.SetError(SVSTREAM_GENERALERROR);
1190 return false;
1193 switch (meType)
1195 case GraphicType::GdiMetafile:
1197 if(!rStream.GetError())
1199 SvmWriter aWriter(rStream);
1200 aWriter.Write(maMetaFile);
1203 break;
1205 case GraphicType::Bitmap:
1207 if (maVectorGraphicData)
1209 rStream.WriteInt32(sal_Int32(GraphicContentType::Vector));
1210 // stream out Vector Graphic defining data (length, byte array and evtl. path)
1211 // this is used e.g. in swapping out graphic data and in transporting it over UNO API
1212 // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
1213 // no problem to extend it; only used at runtime
1214 switch (maVectorGraphicData->getType())
1216 case VectorGraphicDataType::Wmf:
1218 rStream.WriteUInt32(constWmfMagic);
1219 break;
1221 case VectorGraphicDataType::Emf:
1223 rStream.WriteUInt32(constEmfMagic);
1224 break;
1226 case VectorGraphicDataType::Svg:
1228 rStream.WriteUInt32(constSvgMagic);
1229 break;
1231 case VectorGraphicDataType::Pdf:
1233 rStream.WriteUInt32(constPdfMagic);
1234 break;
1238 rStream.WriteUInt32(maVectorGraphicData->getBinaryDataContainer().getSize());
1239 maVectorGraphicData->getBinaryDataContainer().writeToStream(rStream);
1241 else if (mpAnimation)
1243 rStream.WriteInt32(sal_Int32(GraphicContentType::Animation));
1244 WriteAnimation(rStream, *mpAnimation);
1246 else
1248 rStream.WriteInt32(sal_Int32(GraphicContentType::Bitmap));
1249 WriteDIBBitmapEx(maBitmapEx, rStream);
1252 break;
1254 case GraphicType::NONE:
1255 case GraphicType::Default:
1256 break;
1259 if (mpGfxLink)
1260 mpGfxLink->getDataContainer().swapOut();
1262 return true;
1265 bool ImpGraphic::swapOutContent(SvStream& rStream)
1267 ensureAvailable();
1269 bool bRet = false;
1271 if (meType == GraphicType::NONE || meType == GraphicType::Default || isSwappedOut())
1272 return false;
1274 sal_uLong nDataFieldPos;
1276 // Write the SWAP ID
1277 rStream.WriteUInt32(SWAP_FORMAT_ID);
1279 rStream.WriteInt32(static_cast<sal_Int32>(meType));
1281 // data size is updated later
1282 nDataFieldPos = rStream.Tell();
1283 rStream.WriteInt32(0);
1285 // write data block
1286 const sal_uInt64 nDataStart = rStream.Tell();
1288 swapOutGraphic(rStream);
1290 if (!rStream.GetError())
1292 // Write the written length th the header
1293 const sal_uInt64 nCurrentPosition = rStream.Tell();
1294 rStream.Seek(nDataFieldPos);
1295 rStream.WriteInt32(nCurrentPosition - nDataStart);
1296 rStream.Seek(nCurrentPosition);
1297 bRet = true;
1300 return bRet;
1303 bool ImpGraphic::swapOut()
1305 if (isSwappedOut())
1306 return false;
1308 bool bResult = false;
1310 sal_Int64 nByteSize = getSizeBytes();
1312 // We have GfxLink so we have the source available
1313 if (mpGfxLink && mpGfxLink->IsNative())
1315 createSwapInfo();
1317 clearGraphics();
1319 // reset the swap file
1320 mpSwapFile.reset();
1322 // mark as swapped out
1323 mbSwapOut = true;
1325 bResult = true;
1327 else
1329 // Create a swap file
1330 auto pSwapFile = o3tl::make_shared<ImpSwapFile>(getOriginURL());
1332 // Open a stream to write the swap file to
1334 SvStream* pOutputStream = pSwapFile->getStream();
1336 if (!pOutputStream)
1337 return false;
1339 // Write to stream
1340 pOutputStream->SetVersion(SOFFICE_FILEFORMAT_50);
1341 pOutputStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
1342 pOutputStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
1344 if (!pOutputStream->GetError() && swapOutContent(*pOutputStream))
1346 pOutputStream->FlushBuffer();
1347 bResult = !pOutputStream->GetError();
1351 // Check if writing was successful
1352 if (bResult)
1354 // We have swapped out, so can clean memory and prepare swap info
1355 createSwapInfo();
1356 clearGraphics();
1358 mpSwapFile = std::move(pSwapFile);
1359 mbSwapOut = true;
1363 if (bResult)
1365 // Signal to manager that we have swapped out
1366 vcl::graphic::Manager::get().swappedOut(this, nByteSize);
1369 return bResult;
1372 bool ImpGraphic::ensureAvailable() const
1374 auto pThis = const_cast<ImpGraphic*>(this);
1376 bool bResult = true;
1378 if (isSwappedOut())
1379 bResult = pThis->swapIn();
1381 pThis->maLastUsed = std::chrono::high_resolution_clock::now();
1382 return bResult;
1385 void ImpGraphic::updateFromLoadedGraphic(const ImpGraphic* pGraphic)
1387 if (mbPrepared)
1389 GraphicExternalLink aLink = maGraphicExternalLink;
1390 Size aPrefSize = maSwapInfo.maPrefSize;
1391 MapMode aPrefMapMode = maSwapInfo.maPrefMapMode;
1392 *this = *pGraphic;
1393 if (aPrefSize.getWidth() && aPrefSize.getHeight() && aPrefMapMode == getPrefMapMode())
1395 // Use custom preferred size if it was set when the graphic was still unloaded.
1396 // Only set the size in case the unloaded and loaded unit matches.
1397 setPrefSize(aPrefSize);
1399 maGraphicExternalLink = aLink;
1401 else
1403 // Move over only graphic content
1404 mpAnimation.reset();
1405 if (pGraphic->mpAnimation)
1407 mpAnimation = std::make_unique<Animation>(*pGraphic->mpAnimation);
1408 maBitmapEx = mpAnimation->GetBitmapEx();
1410 else
1412 maBitmapEx = pGraphic->maBitmapEx;
1415 maMetaFile = pGraphic->maMetaFile;
1416 maVectorGraphicData = pGraphic->maVectorGraphicData;
1418 // Set to 0, to force recalculation
1419 mnSizeBytes = 0;
1420 mnChecksum = 0;
1422 restoreFromSwapInfo();
1424 mbSwapOut = false;
1428 void ImpGraphic::dumpState(rtl::OStringBuffer &rState)
1430 if (meType == GraphicType::NONE && mnSizeBytes == 0)
1431 return; // uninteresting.
1433 rState.append("\n\t");
1435 if (mbSwapOut)
1436 rState.append("swapped\t");
1437 else
1438 rState.append("loaded\t");
1440 rState.append(static_cast<sal_Int32>(meType));
1441 rState.append("\tsize:\t");
1442 rState.append(static_cast<sal_Int64>(mnSizeBytes));
1443 rState.append("\tgfxl:\t");
1444 rState.append(static_cast<sal_Int64>(mpGfxLink ? mpGfxLink->getSizeBytes() : -1));
1445 rState.append("\t");
1446 rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Width()));
1447 rState.append("x");
1448 rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Height()));
1449 rState.append("\t");
1450 rState.append(static_cast<sal_Int32>(maExPrefSize.Width()));
1451 rState.append("x");
1452 rState.append(static_cast<sal_Int32>(maExPrefSize.Height()));
1455 void ImpGraphic::restoreFromSwapInfo()
1457 setValuesForPrefMapMod(maSwapInfo.maPrefMapMode);
1458 setValuesForPrefSize(maSwapInfo.maPrefSize);
1460 if (maVectorGraphicData)
1462 maVectorGraphicData->setPageIndex(maSwapInfo.mnPageIndex);
1466 namespace
1469 std::optional<VectorGraphicDataType> lclConvertToVectorGraphicType(GfxLink const & rLink)
1471 switch(rLink.GetType())
1473 case GfxLinkType::NativePdf:
1474 return VectorGraphicDataType::Pdf;
1476 case GfxLinkType::NativeWmf:
1477 if (rLink.IsEMF())
1478 return VectorGraphicDataType::Emf;
1479 else
1480 return VectorGraphicDataType::Wmf;
1482 case GfxLinkType::NativeSvg:
1483 return VectorGraphicDataType::Svg;
1485 default:
1486 break;
1488 return std::optional<VectorGraphicDataType>();
1491 } // end namespace
1493 bool ImpGraphic::swapIn()
1495 if (!isSwappedOut())
1496 return false;
1498 bool bReturn = false;
1500 if (mbPrepared)
1502 Graphic aGraphic;
1503 if (!mpGfxLink->LoadNative(aGraphic))
1504 return false;
1506 updateFromLoadedGraphic(aGraphic.ImplGetImpGraphic());
1508 maLastUsed = std::chrono::high_resolution_clock::now();
1509 bReturn = true;
1511 else if (mpGfxLink && mpGfxLink->IsNative())
1513 std::optional<VectorGraphicDataType> oType = lclConvertToVectorGraphicType(*mpGfxLink);
1514 if (oType)
1516 maVectorGraphicData = vcl::loadVectorGraphic(mpGfxLink->getDataContainer(), *oType);
1518 // Set to 0, to force recalculation
1519 mnSizeBytes = 0;
1520 mnChecksum = 0;
1522 restoreFromSwapInfo();
1524 mbSwapOut = false;
1526 else
1528 Graphic aGraphic;
1529 if (!mpGfxLink->LoadNative(aGraphic))
1530 return false;
1532 ImpGraphic* pImpGraphic = aGraphic.ImplGetImpGraphic();
1533 if (meType != pImpGraphic->meType)
1534 return false;
1536 updateFromLoadedGraphic(pImpGraphic);
1539 maLastUsed = std::chrono::high_resolution_clock::now();
1540 bReturn = true;
1542 else
1544 SvStream* pStream = nullptr;
1546 if (mpSwapFile)
1547 pStream = mpSwapFile->getStream();
1549 if (pStream)
1551 pStream->SetVersion(SOFFICE_FILEFORMAT_50);
1552 pStream->SetCompressMode(SvStreamCompressFlags::NATIVE);
1553 pStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE);
1554 pStream->Seek(STREAM_SEEK_TO_BEGIN);
1556 bReturn = swapInFromStream(*pStream);
1558 restoreFromSwapInfo();
1560 setOriginURL(mpSwapFile->getOriginURL());
1562 mpSwapFile.reset();
1566 if (bReturn)
1568 vcl::graphic::Manager::get().swappedIn(this, getSizeBytes());
1571 return bReturn;
1574 bool ImpGraphic::swapInFromStream(SvStream& rStream)
1576 bool bRet = false;
1578 if (rStream.GetError())
1579 return false;
1581 clearGraphics();
1582 mnSizeBytes = 0;
1583 mnChecksum = 0;
1585 bRet = swapInContent(rStream);
1587 if (!bRet)
1589 //throw away swapfile, etc.
1590 clear();
1593 mbSwapOut = false;
1595 return bRet;
1598 bool ImpGraphic::swapInGraphic(SvStream& rStream)
1600 bool bReturn = false;
1602 if (rStream.GetError())
1603 return bReturn;
1605 if (meType == GraphicType::Bitmap)
1607 sal_Int32 nContentType = -1;
1608 rStream.ReadInt32(nContentType);
1609 if (nContentType < 0)
1610 return false;
1612 auto eContentType = static_cast<GraphicContentType>(nContentType);
1614 switch (eContentType)
1616 case GraphicContentType::Bitmap:
1618 BitmapEx aBitmapEx;
1619 ReadDIBBitmapEx(aBitmapEx, rStream);
1620 if (!rStream.GetError())
1622 maBitmapEx = aBitmapEx;
1623 bReturn = true;
1626 break;
1628 case GraphicContentType::Animation:
1630 auto pAnimation = std::make_unique<Animation>();
1631 ReadAnimation(rStream, *pAnimation);
1632 if (!rStream.GetError())
1634 mpAnimation = std::move(pAnimation);
1635 maBitmapEx = mpAnimation->GetBitmapEx();
1636 bReturn = true;
1639 break;
1641 case GraphicContentType::Vector:
1643 // try to stream in Svg defining data (length, byte array and evtl. path)
1644 // See below (operator<<) for more information
1645 sal_uInt32 nMagic;
1646 rStream.ReadUInt32(nMagic);
1648 if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic || constPdfMagic == nMagic)
1650 sal_uInt32 nVectorGraphicDataSize(0);
1651 rStream.ReadUInt32(nVectorGraphicDataSize);
1653 if (nVectorGraphicDataSize)
1655 BinaryDataContainer aDataContainer(rStream, nVectorGraphicDataSize);
1657 if (rStream.GetError())
1658 return false;
1660 VectorGraphicDataType aDataType;
1662 switch (nMagic)
1664 case constSvgMagic:
1665 aDataType = VectorGraphicDataType::Svg;
1666 break;
1667 case constWmfMagic:
1668 aDataType = VectorGraphicDataType::Wmf;
1669 break;
1670 case constEmfMagic:
1671 aDataType = VectorGraphicDataType::Emf;
1672 break;
1673 case constPdfMagic:
1674 aDataType = VectorGraphicDataType::Pdf;
1675 break;
1676 default:
1677 return false;
1680 auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aDataContainer, aDataType);
1682 if (!rStream.GetError())
1684 maVectorGraphicData = aVectorGraphicDataPtr;
1685 bReturn = true;
1690 break;
1693 else if (meType == GraphicType::GdiMetafile)
1695 GDIMetaFile aMetaFile;
1696 SvmReader aReader(rStream);
1697 aReader.Read(aMetaFile);
1698 if (!rStream.GetError())
1700 maMetaFile = aMetaFile;
1701 bReturn = true;
1704 return bReturn;
1707 void ImpGraphic::setGfxLink(const std::shared_ptr<GfxLink>& rGfxLink)
1709 ensureAvailable();
1711 mpGfxLink = rGfxLink;
1714 const std::shared_ptr<GfxLink> & ImpGraphic::getSharedGfxLink() const
1716 return mpGfxLink;
1719 GfxLink ImpGraphic::getGfxLink() const
1721 ensureAvailable();
1723 return( mpGfxLink ? *mpGfxLink : GfxLink() );
1726 bool ImpGraphic::isGfxLink() const
1728 return ( bool(mpGfxLink) );
1731 BitmapChecksum ImpGraphic::getChecksum() const
1733 if (mnChecksum != 0)
1734 return mnChecksum;
1736 ensureAvailable();
1738 switch (meType)
1740 case GraphicType::NONE:
1741 case GraphicType::Default:
1742 break;
1744 case GraphicType::Bitmap:
1746 if (maVectorGraphicData)
1747 mnChecksum = maVectorGraphicData->GetChecksum();
1748 else if (mpAnimation)
1749 mnChecksum = mpAnimation->GetChecksum();
1750 else
1751 mnChecksum = maBitmapEx.GetChecksum();
1753 break;
1755 case GraphicType::GdiMetafile:
1757 mnChecksum = SvmWriter::GetChecksum(maMetaFile);
1759 break;
1761 return mnChecksum;
1764 sal_Int32 ImpGraphic::getPageNumber() const
1766 if (isSwappedOut())
1767 return maSwapInfo.mnPageIndex;
1769 if (maVectorGraphicData)
1770 return maVectorGraphicData->getPageIndex();
1771 return -1;
1773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */