diff options
Diffstat (limited to 'vcl/source/gdi/impgraph.cxx')
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 1775 |
1 files changed, 1775 insertions, 0 deletions
diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx new file mode 100644 index 0000000000..ac36d2c72b --- /dev/null +++ b/vcl/source/gdi/impgraph.cxx @@ -0,0 +1,1775 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <comphelper/fileformat.h> +#include <o3tl/make_shared.hxx> +#include <tools/fract.hxx> +#include <tools/vcompat.hxx> +#include <tools/urlobj.hxx> +#include <tools/stream.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/tempfile.hxx> +#include <utility> +#include <vcl/filter/SvmReader.hxx> +#include <vcl/filter/SvmWriter.hxx> +#include <vcl/outdev.hxx> +#include <vcl/graphicfilter.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gfxlink.hxx> +#include <vcl/cvtgrf.hxx> +#include <vcl/graph.hxx> +#include <vcl/metaact.hxx> +#include <impgraph.hxx> +#include <com/sun/star/graphic/XPrimitive2D.hpp> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <vcl/dibtools.hxx> +#include <map> +#include <memory> +#include <vcl/gdimetafiletools.hxx> +#include <vcl/TypeSerializer.hxx> +#include <vcl/pdfread.hxx> +#include <graphic/VectorGraphicLoader.hxx> + +#define GRAPHIC_MTFTOBMP_MAXEXT 2048 +#define GRAPHIC_STREAMBUFSIZE 8192UL + +#define SWAP_FORMAT_ID COMPAT_FORMAT( 'S', 'W', 'A', 'P' ) + +using namespace com::sun::star; + + +class ImpSwapFile +{ +private: + utl::TempFileFast maTempFile; + OUString maOriginURL; + +public: + ImpSwapFile(OUString aOriginURL) + : maOriginURL(std::move(aOriginURL)) + { + } + + SvStream* getStream() { return maTempFile.GetStream(StreamMode::READWRITE); } + OUString const & getOriginURL() const { return maOriginURL; } +}; + +SvStream* ImpGraphic::getSwapFileStream() const +{ + if (mpSwapFile) + return mpSwapFile->getStream(); + return nullptr; +} + +ImpGraphic::ImpGraphic() : + meType ( GraphicType::NONE ), + mnSizeBytes ( 0 ), + mbSwapOut ( false ), + mbDummyContext ( false ), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared ( false ) +{ +} + +ImpGraphic::ImpGraphic(const ImpGraphic& rImpGraphic) + : maMetaFile(rImpGraphic.maMetaFile) + , maBitmapEx(rImpGraphic.maBitmapEx) + , maSwapInfo(rImpGraphic.maSwapInfo) + , mpContext(rImpGraphic.mpContext) + , mpSwapFile(rImpGraphic.mpSwapFile) + , mpGfxLink(rImpGraphic.mpGfxLink) + , meType(rImpGraphic.meType) + , mnSizeBytes(rImpGraphic.mnSizeBytes) + , mbSwapOut(rImpGraphic.mbSwapOut) + , mbDummyContext(rImpGraphic.mbDummyContext) + , maVectorGraphicData(rImpGraphic.maVectorGraphicData) + , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink) + , maLastUsed (std::chrono::high_resolution_clock::now()) + , mbPrepared (rImpGraphic.mbPrepared) +{ + if( rImpGraphic.mpAnimation ) + { + mpAnimation = std::make_unique<Animation>( *rImpGraphic.mpAnimation ); + maBitmapEx = mpAnimation->GetBitmapEx(); + } +} + +ImpGraphic::ImpGraphic(ImpGraphic&& rImpGraphic) noexcept + : maMetaFile(std::move(rImpGraphic.maMetaFile)) + , maBitmapEx(std::move(rImpGraphic.maBitmapEx)) + , maSwapInfo(std::move(rImpGraphic.maSwapInfo)) + , mpAnimation(std::move(rImpGraphic.mpAnimation)) + , mpContext(std::move(rImpGraphic.mpContext)) + , mpSwapFile(std::move(rImpGraphic.mpSwapFile)) + , mpGfxLink(std::move(rImpGraphic.mpGfxLink)) + , meType(rImpGraphic.meType) + , mnSizeBytes(rImpGraphic.mnSizeBytes) + , mbSwapOut(rImpGraphic.mbSwapOut) + , mbDummyContext(rImpGraphic.mbDummyContext) + , maVectorGraphicData(std::move(rImpGraphic.maVectorGraphicData)) + , maGraphicExternalLink(rImpGraphic.maGraphicExternalLink) + , maLastUsed (std::chrono::high_resolution_clock::now()) + , mbPrepared (rImpGraphic.mbPrepared) +{ + rImpGraphic.clear(); + rImpGraphic.mbDummyContext = false; +} + +ImpGraphic::ImpGraphic(std::shared_ptr<GfxLink> xGfxLink, sal_Int32 nPageIndex) + : mpGfxLink(std::move(xGfxLink)) + , meType(GraphicType::Bitmap) + , mnSizeBytes(0) + , mbSwapOut(true) + , mbDummyContext(false) + , maLastUsed (std::chrono::high_resolution_clock::now()) + , mbPrepared (false) +{ + maSwapInfo.mbIsTransparent = true; + maSwapInfo.mbIsAlpha = true; + maSwapInfo.mbIsEPS = false; + maSwapInfo.mbIsAnimated = false; + maSwapInfo.mnAnimationLoopCount = 0; + maSwapInfo.mnPageIndex = nPageIndex; +} + +ImpGraphic::ImpGraphic(GraphicExternalLink aGraphicExternalLink) : + meType ( GraphicType::Default ), + mnSizeBytes ( 0 ), + mbSwapOut ( false ), + mbDummyContext ( false ), + maGraphicExternalLink(std::move(aGraphicExternalLink)), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared (false) +{ +} + +ImpGraphic::ImpGraphic( const BitmapEx& rBitmapEx ) : + maBitmapEx ( rBitmapEx ), + meType ( !rBitmapEx.IsEmpty() ? GraphicType::Bitmap : GraphicType::NONE ), + mnSizeBytes ( 0 ), + mbSwapOut ( false ), + mbDummyContext ( false ), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared (false) +{ +} + +ImpGraphic::ImpGraphic(const std::shared_ptr<VectorGraphicData>& rVectorGraphicDataPtr) +: meType( rVectorGraphicDataPtr ? GraphicType::Bitmap : GraphicType::NONE ), + mnSizeBytes( 0 ), + mbSwapOut( false ), + mbDummyContext ( false ), + maVectorGraphicData(rVectorGraphicDataPtr), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared (false) +{ +} + +ImpGraphic::ImpGraphic( const Animation& rAnimation ) : + maBitmapEx ( rAnimation.GetBitmapEx() ), + mpAnimation ( std::make_unique<Animation>( rAnimation ) ), + meType ( GraphicType::Bitmap ), + mnSizeBytes ( 0 ), + mbSwapOut ( false ), + mbDummyContext ( false ), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared (false) +{ +} + +ImpGraphic::ImpGraphic( const GDIMetaFile& rMtf ) : + maMetaFile ( rMtf ), + meType ( GraphicType::GdiMetafile ), + mnSizeBytes ( 0 ), + mbSwapOut ( false ), + mbDummyContext ( false ), + maLastUsed (std::chrono::high_resolution_clock::now()), + mbPrepared (false) +{ +} + +ImpGraphic::~ImpGraphic() +{ + vcl::graphic::Manager::get().unregisterGraphic(this); +} + +ImpGraphic& ImpGraphic::operator=( const ImpGraphic& rImpGraphic ) +{ + if( &rImpGraphic != this ) + { + sal_Int64 aOldSizeBytes = mnSizeBytes; + + maMetaFile = rImpGraphic.maMetaFile; + meType = rImpGraphic.meType; + mnSizeBytes = rImpGraphic.mnSizeBytes; + + maSwapInfo = rImpGraphic.maSwapInfo; + mpContext = rImpGraphic.mpContext; + mbDummyContext = rImpGraphic.mbDummyContext; + maGraphicExternalLink = rImpGraphic.maGraphicExternalLink; + + mpAnimation.reset(); + + if ( rImpGraphic.mpAnimation ) + { + mpAnimation = std::make_unique<Animation>( *rImpGraphic.mpAnimation ); + maBitmapEx = mpAnimation->GetBitmapEx(); + } + else + { + maBitmapEx = rImpGraphic.maBitmapEx; + } + + mbSwapOut = rImpGraphic.mbSwapOut; + mpSwapFile = rImpGraphic.mpSwapFile; + mbPrepared = rImpGraphic.mbPrepared; + + mpGfxLink = rImpGraphic.mpGfxLink; + + maVectorGraphicData = rImpGraphic.maVectorGraphicData; + maLastUsed = std::chrono::high_resolution_clock::now(); + + vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes); + } + + return *this; +} + +ImpGraphic& ImpGraphic::operator=(ImpGraphic&& rImpGraphic) +{ + sal_Int64 aOldSizeBytes = mnSizeBytes; + + maMetaFile = std::move(rImpGraphic.maMetaFile); + meType = rImpGraphic.meType; + mnSizeBytes = rImpGraphic.mnSizeBytes; + maSwapInfo = std::move(rImpGraphic.maSwapInfo); + mpContext = std::move(rImpGraphic.mpContext); + mbDummyContext = rImpGraphic.mbDummyContext; + mpAnimation = std::move(rImpGraphic.mpAnimation); + maBitmapEx = std::move(rImpGraphic.maBitmapEx); + mbSwapOut = rImpGraphic.mbSwapOut; + mpSwapFile = std::move(rImpGraphic.mpSwapFile); + mpGfxLink = std::move(rImpGraphic.mpGfxLink); + maVectorGraphicData = std::move(rImpGraphic.maVectorGraphicData); + maGraphicExternalLink = rImpGraphic.maGraphicExternalLink; + mbPrepared = rImpGraphic.mbPrepared; + + rImpGraphic.clear(); + rImpGraphic.mbDummyContext = false; + maLastUsed = std::chrono::high_resolution_clock::now(); + + vcl::graphic::Manager::get().changeExisting(this, aOldSizeBytes); + + return *this; +} + +bool ImpGraphic::operator==( const ImpGraphic& rOther ) const +{ + if( this == &rOther ) + return true; + + if (mbPrepared && rOther.mbPrepared) + return (*mpGfxLink == *rOther.mpGfxLink); + + if (!isAvailable() || !rOther.isAvailable()) + return false; + + if ( meType != rOther.meType ) + return false; + + bool bRet = false; + switch( meType ) + { + case GraphicType::NONE: + case GraphicType::Default: + return true; + + case GraphicType::GdiMetafile: + return ( rOther.maMetaFile == maMetaFile ); + + case GraphicType::Bitmap: + { + if(maVectorGraphicData) + { + if(maVectorGraphicData == rOther.maVectorGraphicData) + { + // equal instances + bRet = true; + } + else if(rOther.maVectorGraphicData) + { + // equal content + bRet = (*maVectorGraphicData) == (*rOther.maVectorGraphicData); + } + } + else if( mpAnimation ) + { + if( rOther.mpAnimation && ( *rOther.mpAnimation == *mpAnimation ) ) + bRet = true; + } + else if( !rOther.mpAnimation && ( rOther.maBitmapEx == maBitmapEx ) ) + { + bRet = true; + } + } + break; + } + + return bRet; +} + +const std::shared_ptr<VectorGraphicData>& ImpGraphic::getVectorGraphicData() const +{ + ensureAvailable(); + + return maVectorGraphicData; +} + +void ImpGraphic::createSwapInfo() +{ + if (isSwappedOut()) + return; + + if (!maBitmapEx.IsEmpty()) + maSwapInfo.maSizePixel = maBitmapEx.GetSizePixel(); + else + maSwapInfo.maSizePixel = Size(); + + maSwapInfo.maPrefMapMode = getPrefMapMode(); + maSwapInfo.maPrefSize = getPrefSize(); + maSwapInfo.mbIsAnimated = isAnimated(); + maSwapInfo.mbIsEPS = isEPS(); + maSwapInfo.mbIsTransparent = isTransparent(); + maSwapInfo.mbIsAlpha = isAlpha(); + maSwapInfo.mnAnimationLoopCount = getAnimationLoopCount(); + maSwapInfo.mnPageIndex = getPageNumber(); +} + +void ImpGraphic::clearGraphics() +{ + maBitmapEx.Clear(); + maMetaFile.Clear(); + mpAnimation.reset(); + maVectorGraphicData.reset(); +} + +void ImpGraphic::setPrepared(bool bAnimated, const Size* pSizeHint) +{ + mbPrepared = true; + mbSwapOut = true; + meType = GraphicType::Bitmap; + + SvMemoryStream aMemoryStream(const_cast<sal_uInt8*>(mpGfxLink->GetData()), mpGfxLink->GetDataSize(), StreamMode::READ | StreamMode::WRITE); + + if (pSizeHint) + { + maSwapInfo.maPrefSize = *pSizeHint; + maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM); + } + + GraphicDescriptor aDescriptor(aMemoryStream, nullptr); + if (aDescriptor.Detect(true)) + { + if (!pSizeHint) + { + // If we have logic size, work with that, as later pixel -> logic + // conversion will work with the output device DPI, not the graphic + // DPI. + Size aLogSize = aDescriptor.GetSize_100TH_MM(); + if (aDescriptor.GetPreferredLogSize() && aDescriptor.GetPreferredMapMode()) + { + maSwapInfo.maPrefSize = *aDescriptor.GetPreferredLogSize(); + maSwapInfo.maPrefMapMode = *aDescriptor.GetPreferredMapMode(); + } + else if (aLogSize.getWidth() && aLogSize.getHeight()) + { + maSwapInfo.maPrefSize = aLogSize; + maSwapInfo.maPrefMapMode = MapMode(MapUnit::Map100thMM); + } + else + { + maSwapInfo.maPrefSize = aDescriptor.GetSizePixel(); + maSwapInfo.maPrefMapMode = MapMode(MapUnit::MapPixel); + } + } + + maSwapInfo.maSizePixel = aDescriptor.GetSizePixel(); + maSwapInfo.mbIsTransparent = aDescriptor.IsTransparent(); + maSwapInfo.mbIsAlpha = aDescriptor.IsAlpha(); + } else { + maSwapInfo.mbIsTransparent = false; + maSwapInfo.mbIsAlpha = false; + } + + maSwapInfo.mnAnimationLoopCount = 0; + maSwapInfo.mbIsEPS = false; + maSwapInfo.mbIsAnimated = bAnimated; + + if (maVectorGraphicData) + maSwapInfo.mnPageIndex = maVectorGraphicData->getPageIndex(); +} + +void ImpGraphic::clear() +{ + mpSwapFile.reset(); + mbSwapOut = false; + mbPrepared = false; + + // cleanup + clearGraphics(); + meType = GraphicType::NONE; + sal_Int64 nOldSize = mnSizeBytes; + mnSizeBytes = 0; + vcl::graphic::Manager::get().changeExisting(this, nOldSize); + maGraphicExternalLink.msURL.clear(); +} + +void ImpGraphic::setDefaultType() +{ + clear(); + meType = GraphicType::Default; +} + +bool ImpGraphic::isSupportedGraphic() const +{ + return( meType != GraphicType::NONE ); +} + +bool ImpGraphic::isTransparent() const +{ + bool bRet(true); + + if (mbSwapOut) + { + bRet = maSwapInfo.mbIsTransparent; + } + else if (meType == GraphicType::Bitmap && !maVectorGraphicData) + { + bRet = mpAnimation ? mpAnimation->IsTransparent() : maBitmapEx.IsAlpha(); + } + + return bRet; +} + +bool ImpGraphic::isAlpha() const +{ + bool bRet(false); + + if (mbSwapOut) + { + bRet = maSwapInfo.mbIsAlpha; + } + else if (maVectorGraphicData) + { + bRet = true; + } + else if (meType == GraphicType::Bitmap) + { + bRet = (nullptr == mpAnimation && maBitmapEx.IsAlpha()); + } + + return bRet; +} + +bool ImpGraphic::isAnimated() const +{ + return mbSwapOut ? maSwapInfo.mbIsAnimated : mpAnimation != nullptr; +} + +bool ImpGraphic::isEPS() const +{ + if (mbSwapOut) + return maSwapInfo.mbIsEPS; + + return( ( meType == GraphicType::GdiMetafile ) && + ( maMetaFile.GetActionSize() > 0 ) && + ( maMetaFile.GetAction( 0 )->GetType() == MetaActionType::EPS ) ); +} + +bool ImpGraphic::isAvailable() const +{ + return !mbPrepared && !mbSwapOut; +} + +bool ImpGraphic::makeAvailable() +{ + return ensureAvailable(); +} + +BitmapEx ImpGraphic::getVectorGraphicReplacement() const +{ + BitmapEx aRet = maVectorGraphicData->getReplacement(); + + if (maExPrefSize.getWidth() && maExPrefSize.getHeight()) + { + aRet.SetPrefSize(maExPrefSize); + } + + return aRet; +} + +Bitmap ImpGraphic::getBitmap(const GraphicConversionParameters& rParameters) const +{ + Bitmap aRetBmp; + + ensureAvailable(); + + if( meType == GraphicType::Bitmap ) + { + if(maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // use maBitmapEx as local buffer for rendered svg + const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement(); + } + + const BitmapEx& rRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx ); + + aRetBmp = rRetBmpEx.GetBitmap( COL_WHITE ); + + if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height()) + aRetBmp.Scale(rParameters.getSizePixel()); + } + else if( ( meType != GraphicType::Default ) && isSupportedGraphic() ) + { + if(maBitmapEx.IsEmpty()) + { + // calculate size + ScopedVclPtrInstance< VirtualDevice > aVDev; + Size aDrawSize(aVDev->LogicToPixel(maMetaFile.GetPrefSize(), maMetaFile.GetPrefMapMode())); + + if(rParameters.getSizePixel().Width() && rParameters.getSizePixel().Height()) + { + // apply given size if exists + aDrawSize = rParameters.getSizePixel(); + } + + if(aDrawSize.Width() && aDrawSize.Height() && !rParameters.getUnlimitedSize() + && (aDrawSize.Width() > GRAPHIC_MTFTOBMP_MAXEXT || aDrawSize.Height() > GRAPHIC_MTFTOBMP_MAXEXT)) + { + // limit bitmap size to a maximum of GRAPHIC_MTFTOBMP_MAXEXT x GRAPHIC_MTFTOBMP_MAXEXT + double fWH(static_cast<double>(aDrawSize.Width()) / static_cast<double>(aDrawSize.Height())); + + if(fWH <= 1.0) + { + aDrawSize.setWidth(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT * fWH)); + aDrawSize.setHeight(GRAPHIC_MTFTOBMP_MAXEXT); + } + else + { + aDrawSize.setWidth(GRAPHIC_MTFTOBMP_MAXEXT); + aDrawSize.setHeight(basegfx::fround(GRAPHIC_MTFTOBMP_MAXEXT / fWH)); + } + } + + // calculate pixel size. Normally, it's the same as aDrawSize, but may + // need to be extended when hairlines are on the right or bottom edge + Size aPixelSize(aDrawSize); + + if(GraphicType::GdiMetafile == getType()) + { + // tdf#126319 Removed correction based on hairline-at-the-extremes of + // the metafile. The task shows that this is no longer sufficient since + // less hairlines get used in general - what is good, but breaks that + // old fix. Anyways, hairlines are a left-over from non-AA times + // when it was not possible to paint lines taller than one pixel. + // This might need to be corrected further using primitives and + // the possibility to get better-quality ranges for correction. For + // now, always add that one pixel. + aPixelSize.setWidth(aPixelSize.getWidth() + 1); + aPixelSize.setHeight(aPixelSize.getHeight() + 1); + } + + if(aVDev->SetOutputSizePixel(aPixelSize)) + { + if(rParameters.getAntiAliase()) + { + aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::Enable); + } + + if(rParameters.getSnapHorVerLines()) + { + aVDev->SetAntialiasing(aVDev->GetAntialiasing() | AntialiasingFlags::PixelSnapHairline); + } + + draw(*aVDev, Point(), aDrawSize); + + // use maBitmapEx as local buffer for rendered metafile + const_cast< ImpGraphic* >(this)->maBitmapEx = aVDev->GetBitmapEx( Point(), aVDev->GetOutputSizePixel() ); + } + } + + aRetBmp = maBitmapEx.GetBitmap(); + } + + if( !aRetBmp.IsEmpty() ) + { + aRetBmp.SetPrefMapMode(getPrefMapMode()); + aRetBmp.SetPrefSize(getPrefSize()); + } + + return aRetBmp; +} + +BitmapEx ImpGraphic::getBitmapEx(const GraphicConversionParameters& rParameters) const +{ + BitmapEx aRetBmpEx; + + ensureAvailable(); + + if( meType == GraphicType::Bitmap ) + { + if(maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // use maBitmapEx as local buffer for rendered svg + const_cast< ImpGraphic* >(this)->maBitmapEx = getVectorGraphicReplacement(); + } + + aRetBmpEx = ( mpAnimation ? mpAnimation->GetBitmapEx() : maBitmapEx ); + + if(rParameters.getSizePixel().Width() || rParameters.getSizePixel().Height()) + { + aRetBmpEx.Scale( + rParameters.getSizePixel(), + BmpScaleFlag::Fast); + } + } + else if( ( meType != GraphicType::Default ) && isSupportedGraphic() ) + { + if(maBitmapEx.IsEmpty()) + { + const ImpGraphic aMonoMask( maMetaFile.GetMonochromeMtf( COL_BLACK ) ); + + // use maBitmapEx as local buffer for rendered metafile + const_cast< ImpGraphic* >(this)->maBitmapEx = BitmapEx(getBitmap(rParameters), aMonoMask.getBitmap(rParameters)); + } + + aRetBmpEx = maBitmapEx; + } + + return aRetBmpEx; +} + +Animation ImpGraphic::getAnimation() const +{ + Animation aAnimation; + + ensureAvailable(); + if( mpAnimation ) + aAnimation = *mpAnimation; + + return aAnimation; +} + +const BitmapEx& ImpGraphic::getBitmapExRef() const +{ + ensureAvailable(); + return maBitmapEx; +} + +const GDIMetaFile& ImpGraphic::getGDIMetaFile() const +{ + ensureAvailable(); + if (!maMetaFile.GetActionSize() + && maVectorGraphicData + && (VectorGraphicDataType::Emf == maVectorGraphicData->getType() + || VectorGraphicDataType::Wmf == maVectorGraphicData->getType())) + { + // If we have a Emf/Wmf VectorGraphic object, we + // need a way to get the Metafile data out of the primitive + // representation. Use a strict virtual hook (MetafileAccessor) + // to access the MetafilePrimitive2D directly. Also see comments in + // XEmfParser about this. + const std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > aSequence(maVectorGraphicData->getPrimitive2DSequence()); + + if (1 == aSequence.size()) + { + // try to cast to MetafileAccessor implementation + const css::uno::Reference< css::graphic::XPrimitive2D > xReference(aSequence[0]); + auto pUnoPrimitive = static_cast< const drawinglayer::primitive2d::UnoPrimitive2D* >(xReference.get()); + if (pUnoPrimitive) + { + const MetafileAccessor* pMetafileAccessor = dynamic_cast< const MetafileAccessor* >(pUnoPrimitive->getBasePrimitive2D().get()); + + if (pMetafileAccessor) + { + // it is a MetafileAccessor implementation, get Metafile + pMetafileAccessor->accessMetafile(const_cast< ImpGraphic* >(this)->maMetaFile); + } + } + } + } + + if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize()) + { + // #i119735# + // Use the local maMetaFile as container for a metafile-representation + // of the bitmap graphic. This will be done only once, thus be buffered. + // I checked all usages of maMetaFile, it is only used when type is not + // GraphicType::Bitmap. In operator= it will get copied, thus buffering will + // survive copying (change this if not wanted) + ImpGraphic* pThat = const_cast< ImpGraphic* >(this); + + if(maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // use maBitmapEx as local buffer for rendered svg + pThat->maBitmapEx = getVectorGraphicReplacement(); + } + + // #123983# directly create a metafile with the same PrefSize and PrefMapMode + // the bitmap has, this will be an always correct metafile + if(maBitmapEx.IsAlpha()) + { + pThat->maMetaFile.AddAction(new MetaBmpExScaleAction(Point(), maBitmapEx.GetPrefSize(), maBitmapEx)); + } + else + { + pThat->maMetaFile.AddAction(new MetaBmpScaleAction(Point(), maBitmapEx.GetPrefSize(), maBitmapEx.GetBitmap())); + } + + pThat->maMetaFile.Stop(); + pThat->maMetaFile.WindStart(); + pThat->maMetaFile.SetPrefSize(maBitmapEx.GetPrefSize()); + pThat->maMetaFile.SetPrefMapMode(maBitmapEx.GetPrefMapMode()); + } + + return maMetaFile; +} + +Size ImpGraphic::getSizePixel() const +{ + Size aSize; + + if (isSwappedOut()) + aSize = maSwapInfo.maSizePixel; + else + aSize = getBitmapEx(GraphicConversionParameters()).GetSizePixel(); + + return aSize; +} + +Size ImpGraphic::getPrefSize() const +{ + Size aSize; + + if (isSwappedOut()) + { + aSize = maSwapInfo.maPrefSize; + } + else + { + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData && maBitmapEx.IsEmpty()) + { + if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight()) + { + // svg not yet buffered in maBitmapEx, return size derived from range + const basegfx::B2DRange& rRange = maVectorGraphicData->getRange(); + +#ifdef MACOSX + // tdf#157680 scale down estimated size of embedded PDF + // For some unknown reason, the embedded PDF sizes + // are 20x larger than expected. This only occurs on + // macOS so possibly there is some special conversion + // from MapUnit::MapPoint to MapUnit::MapTwip elsewhere + // in the code. + if (maVectorGraphicData->getType() == VectorGraphicDataType::Pdf) + aSize = Size(basegfx::fround(rRange.getWidth() / 20.0f), basegfx::fround(rRange.getHeight() / 20.0f)); + else +#endif + aSize = Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight())); + } + else + { + aSize = maExPrefSize; + } + } + else + { + aSize = maBitmapEx.GetPrefSize(); + + if( !aSize.Width() || !aSize.Height() ) + { + aSize = maBitmapEx.GetSizePixel(); + } + } + } + break; + + case GraphicType::GdiMetafile: + { + aSize = maMetaFile.GetPrefSize(); + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } + } + + return aSize; +} + +void ImpGraphic::setValuesForPrefSize(const Size& rPrefSize) +{ + switch (meType) + { + case GraphicType::Bitmap: + { + // used when importing a writer FlyFrame with SVG as graphic, added conversion + // to allow setting the PrefSize at the BitmapEx to hold it + if (maVectorGraphicData && maBitmapEx.IsEmpty()) + { + maExPrefSize = rPrefSize; + } + + // #108077# Push through pref size to animation object, + // will be lost on copy otherwise + if (mpAnimation) + { + const_cast< BitmapEx& >(mpAnimation->GetBitmapEx()).SetPrefSize(rPrefSize); + } + + if (!maExPrefSize.getWidth() || !maExPrefSize.getHeight()) + { + maBitmapEx.SetPrefSize(rPrefSize); + } + } + break; + + case GraphicType::GdiMetafile: + { + if (isSupportedGraphic()) + maMetaFile.SetPrefSize(rPrefSize); + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } +} + +void ImpGraphic::setPrefSize(const Size& rPrefSize) +{ + ensureAvailable(); + setValuesForPrefSize(rPrefSize); +} + +MapMode ImpGraphic::getPrefMapMode() const +{ + MapMode aMapMode; + + if (isSwappedOut()) + { + aMapMode = maSwapInfo.maPrefMapMode; + } + else + { + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // svg not yet buffered in maBitmapEx, return default PrefMapMode + aMapMode = MapMode(MapUnit::Map100thMM); + } + else + { + const Size aSize(maBitmapEx.GetPrefSize()); + + if (aSize.Width() && aSize.Height()) + aMapMode = maBitmapEx.GetPrefMapMode(); + } + } + break; + + case GraphicType::GdiMetafile: + { + return maMetaFile.GetPrefMapMode(); + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } + } + + return aMapMode; +} + +void ImpGraphic::setValuesForPrefMapMod(const MapMode& rPrefMapMode) +{ + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData) + { + // ignore for Vector Graphic Data. If this is really used (except the grfcache) + // it can be extended by using maBitmapEx as buffer for getVectorGraphicReplacement() + } + else + { + // #108077# Push through pref mapmode to animation object, + // will be lost on copy otherwise + if (mpAnimation) + { + const_cast<BitmapEx&>(mpAnimation->GetBitmapEx()).SetPrefMapMode(rPrefMapMode); + } + + maBitmapEx.SetPrefMapMode(rPrefMapMode); + } + } + break; + + case GraphicType::GdiMetafile: + { + maMetaFile.SetPrefMapMode(rPrefMapMode); + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } +} + +void ImpGraphic::setPrefMapMode(const MapMode& rPrefMapMode) +{ + ensureAvailable(); + setValuesForPrefMapMod(rPrefMapMode); +} + +sal_uLong ImpGraphic::getSizeBytes() const +{ + if (mnSizeBytes > 0) + return mnSizeBytes; + + if (mbPrepared) + ensureAvailable(); + + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData) + { + std::pair<VectorGraphicData::State, size_t> aPair(maVectorGraphicData->getSizeBytes()); + if (VectorGraphicData::State::UNPARSED == aPair.first) + { + return aPair.second; // don't cache it until Vector Graphic Data is parsed + } + mnSizeBytes = aPair.second; + } + else + { + mnSizeBytes = mpAnimation ? mpAnimation->GetSizeBytes() : maBitmapEx.GetSizeBytes(); + } + } + break; + + case GraphicType::GdiMetafile: + { + mnSizeBytes = maMetaFile.GetSizeBytes(); + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } + + return mnSizeBytes; +} + +void ImpGraphic::draw(OutputDevice& rOutDev, const Point& rDestPt) const +{ + ensureAvailable(); + + if (isSwappedOut()) + return; + + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // use maBitmapEx as local buffer for rendered svg + const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement(); + } + + if (mpAnimation) + { + mpAnimation->Draw(rOutDev, rDestPt); + } + else + { + maBitmapEx.Draw(&rOutDev, rDestPt); + } + } + break; + + case GraphicType::GdiMetafile: + { + draw(rOutDev, rDestPt, maMetaFile.GetPrefSize()); + } + break; + + case GraphicType::Default: + case GraphicType::NONE: + break; + } +} + +void ImpGraphic::draw(OutputDevice& rOutDev, + const Point& rDestPt, const Size& rDestSize) const +{ + ensureAvailable(); + + if (isSwappedOut()) + return; + + switch (meType) + { + case GraphicType::Bitmap: + { + if (maVectorGraphicData && maBitmapEx.IsEmpty()) + { + // use maBitmapEx as local buffer for rendered svg + const_cast<ImpGraphic*>(this)->maBitmapEx = getVectorGraphicReplacement(); + } + + if (mpAnimation) + { + mpAnimation->Draw(rOutDev, rDestPt, rDestSize); + } + else + { + maBitmapEx.Draw(&rOutDev, rDestPt, rDestSize); + } + } + break; + + case GraphicType::GdiMetafile: + { + const_cast<ImpGraphic*>(this)->maMetaFile.WindStart(); + const_cast<ImpGraphic*>(this)->maMetaFile.Play(rOutDev, rDestPt, rDestSize); + const_cast<ImpGraphic*>(this)->maMetaFile.WindStart(); + } + break; + + case GraphicType::Default: + case GraphicType::NONE: + break; + } +} + +void ImpGraphic::startAnimation(OutputDevice& rOutDev, const Point& rDestPt, + const Size& rDestSize, tools::Long nRendererId, + OutputDevice* pFirstFrameOutDev ) +{ + ensureAvailable(); + + if( isSupportedGraphic() && !isSwappedOut() && mpAnimation ) + mpAnimation->Start(rOutDev, rDestPt, rDestSize, nRendererId, pFirstFrameOutDev); +} + +void ImpGraphic::stopAnimation( const OutputDevice* pOutDev, tools::Long nRendererId ) +{ + ensureAvailable(); + + if( isSupportedGraphic() && !isSwappedOut() && mpAnimation ) + mpAnimation->Stop( pOutDev, nRendererId ); +} + +void ImpGraphic::setAnimationNotifyHdl( const Link<Animation*,void>& rLink ) +{ + ensureAvailable(); + + if( mpAnimation ) + mpAnimation->SetNotifyHdl( rLink ); +} + +Link<Animation*,void> ImpGraphic::getAnimationNotifyHdl() const +{ + Link<Animation*,void> aLink; + + ensureAvailable(); + + if( mpAnimation ) + aLink = mpAnimation->GetNotifyHdl(); + + return aLink; +} + +sal_uInt32 ImpGraphic::getAnimationLoopCount() const +{ + if (mbSwapOut) + return maSwapInfo.mnAnimationLoopCount; + + return mpAnimation ? mpAnimation->GetLoopCount() : 0; +} + +void ImpGraphic::setContext( const std::shared_ptr<GraphicReader>& pReader ) +{ + mpContext = pReader; + mbDummyContext = false; +} + +bool ImpGraphic::swapInContent(SvStream& rStream) +{ + bool bRet = false; + + sal_uInt32 nId; + sal_Int32 nType; + sal_Int32 nLength; + + rStream.ReadUInt32(nId); + + // check version + if (SWAP_FORMAT_ID != nId) + { + SAL_WARN("vcl", "Incompatible swap file!"); + return false; + } + + rStream.ReadInt32(nType); + rStream.ReadInt32(nLength); + + meType = static_cast<GraphicType>(nType); + + if (meType == GraphicType::NONE || meType == GraphicType::Default) + { + return true; + } + else + { + bRet = swapInGraphic(rStream); + } + + return bRet; +} + +bool ImpGraphic::swapOutGraphic(SvStream& rStream) +{ + if (rStream.GetError()) + return false; + + ensureAvailable(); + + if (isSwappedOut()) + { + rStream.SetError(SVSTREAM_GENERALERROR); + return false; + } + + switch (meType) + { + case GraphicType::GdiMetafile: + { + if(!rStream.GetError()) + { + SvmWriter aWriter(rStream); + aWriter.Write(maMetaFile); + } + } + break; + + case GraphicType::Bitmap: + { + if (maVectorGraphicData) + { + rStream.WriteInt32(sal_Int32(GraphicContentType::Vector)); + // stream out Vector Graphic defining data (length, byte array and evtl. path) + // this is used e.g. in swapping out graphic data and in transporting it over UNO API + // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be + // no problem to extend it; only used at runtime + switch (maVectorGraphicData->getType()) + { + case VectorGraphicDataType::Wmf: + { + rStream.WriteUInt32(constWmfMagic); + break; + } + case VectorGraphicDataType::Emf: + { + rStream.WriteUInt32(constEmfMagic); + break; + } + case VectorGraphicDataType::Svg: + { + rStream.WriteUInt32(constSvgMagic); + break; + } + case VectorGraphicDataType::Pdf: + { + rStream.WriteUInt32(constPdfMagic); + break; + } + } + + rStream.WriteUInt32(maVectorGraphicData->getBinaryDataContainer().getSize()); + maVectorGraphicData->getBinaryDataContainer().writeToStream(rStream); + } + else if (mpAnimation) + { + rStream.WriteInt32(sal_Int32(GraphicContentType::Animation)); + WriteAnimation(rStream, *mpAnimation); + } + else + { + rStream.WriteInt32(sal_Int32(GraphicContentType::Bitmap)); + WriteDIBBitmapEx(maBitmapEx, rStream); + } + } + break; + + case GraphicType::NONE: + case GraphicType::Default: + break; + } + + if (mpGfxLink) + mpGfxLink->getDataContainer().swapOut(); + + return true; +} + +bool ImpGraphic::swapOutContent(SvStream& rStream) +{ + ensureAvailable(); + + bool bRet = false; + + if (meType == GraphicType::NONE || meType == GraphicType::Default || isSwappedOut()) + return false; + + sal_uLong nDataFieldPos; + + // Write the SWAP ID + rStream.WriteUInt32(SWAP_FORMAT_ID); + + rStream.WriteInt32(static_cast<sal_Int32>(meType)); + + // data size is updated later + nDataFieldPos = rStream.Tell(); + rStream.WriteInt32(0); + + // write data block + const sal_uInt64 nDataStart = rStream.Tell(); + + swapOutGraphic(rStream); + + if (!rStream.GetError()) + { + // Write the written length th the header + const sal_uInt64 nCurrentPosition = rStream.Tell(); + rStream.Seek(nDataFieldPos); + rStream.WriteInt32(nCurrentPosition - nDataStart); + rStream.Seek(nCurrentPosition); + bRet = true; + } + + return bRet; +} + +bool ImpGraphic::swapOut() +{ + if (isSwappedOut()) + return false; + + bool bResult = false; + + sal_Int64 nByteSize = getSizeBytes(); + + // We have GfxLink so we have the source available + if (mpGfxLink && mpGfxLink->IsNative()) + { + createSwapInfo(); + + clearGraphics(); + + // reset the swap file + mpSwapFile.reset(); + + mpGfxLink->getDataContainer().swapOut(); + + // mark as swapped out + mbSwapOut = true; + + bResult = true; + } + else + { + // Create a swap file + auto pSwapFile = o3tl::make_shared<ImpSwapFile>(getOriginURL()); + + // Open a stream to write the swap file to + { + SvStream* pOutputStream = pSwapFile->getStream(); + + if (!pOutputStream) + return false; + + // Write to stream + pOutputStream->SetVersion(SOFFICE_FILEFORMAT_50); + pOutputStream->SetCompressMode(SvStreamCompressFlags::NATIVE); + pOutputStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE); + + if (!pOutputStream->GetError() && swapOutContent(*pOutputStream)) + { + pOutputStream->FlushBuffer(); + bResult = !pOutputStream->GetError(); + } + } + + // Check if writing was successful + if (bResult) + { + // We have swapped out, so can clean memory and prepare swap info + createSwapInfo(); + clearGraphics(); + + mpSwapFile = std::move(pSwapFile); + mbSwapOut = true; + } + } + + if (bResult) + { + // Signal to manager that we have swapped out + vcl::graphic::Manager::get().swappedOut(this, nByteSize); + } + + return bResult; +} + +bool ImpGraphic::ensureAvailable() const +{ + auto pThis = const_cast<ImpGraphic*>(this); + + bool bResult = true; + + if (isSwappedOut()) + bResult = pThis->swapIn(); + + pThis->maLastUsed = std::chrono::high_resolution_clock::now(); + return bResult; +} + +void ImpGraphic::updateFromLoadedGraphic(const ImpGraphic* pGraphic) +{ + if (mbPrepared) + { + GraphicExternalLink aLink = maGraphicExternalLink; + Size aPrefSize = maSwapInfo.maPrefSize; + MapMode aPrefMapMode = maSwapInfo.maPrefMapMode; + *this = *pGraphic; + if (aPrefSize.getWidth() && aPrefSize.getHeight() && aPrefMapMode == getPrefMapMode()) + { + // Use custom preferred size if it was set when the graphic was still unloaded. + // Only set the size in case the unloaded and loaded unit matches. + setPrefSize(aPrefSize); + } + maGraphicExternalLink = aLink; + } + else + { + // Move over only graphic content + mpAnimation.reset(); + if (pGraphic->mpAnimation) + { + mpAnimation = std::make_unique<Animation>(*pGraphic->mpAnimation); + maBitmapEx = mpAnimation->GetBitmapEx(); + } + else + { + maBitmapEx = pGraphic->maBitmapEx; + } + + maMetaFile = pGraphic->maMetaFile; + maVectorGraphicData = pGraphic->maVectorGraphicData; + + // Set to 0, to force recalculation + mnSizeBytes = 0; + mnChecksum = 0; + + restoreFromSwapInfo(); + + mbSwapOut = false; + } +} + +void ImpGraphic::dumpState(rtl::OStringBuffer &rState) +{ + if (meType == GraphicType::NONE && mnSizeBytes == 0) + return; // uninteresting. + + rState.append("\n\t"); + + if (mbSwapOut) + rState.append("swapped\t"); + else + rState.append("loaded\t"); + + rState.append(static_cast<sal_Int32>(meType)); + rState.append("\tsize:\t"); + rState.append(static_cast<sal_Int64>(mnSizeBytes)); + rState.append("\tgfxl:\t"); + rState.append(static_cast<sal_Int64>(mpGfxLink ? mpGfxLink->getSizeBytes() : -1)); + rState.append("\t"); + rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Width())); + rState.append("x"); + rState.append(static_cast<sal_Int32>(maSwapInfo.maSizePixel.Height())); + rState.append("\t"); + rState.append(static_cast<sal_Int32>(maExPrefSize.Width())); + rState.append("x"); + rState.append(static_cast<sal_Int32>(maExPrefSize.Height())); +} + +void ImpGraphic::restoreFromSwapInfo() +{ + setValuesForPrefMapMod(maSwapInfo.maPrefMapMode); + setValuesForPrefSize(maSwapInfo.maPrefSize); + + if (maVectorGraphicData) + { + maVectorGraphicData->setPageIndex(maSwapInfo.mnPageIndex); + } +} + +namespace +{ + +std::optional<VectorGraphicDataType> lclConvertToVectorGraphicType(GfxLink const & rLink) +{ + switch(rLink.GetType()) + { + case GfxLinkType::NativePdf: + return VectorGraphicDataType::Pdf; + + case GfxLinkType::NativeWmf: + if (rLink.IsEMF()) + return VectorGraphicDataType::Emf; + else + return VectorGraphicDataType::Wmf; + + case GfxLinkType::NativeSvg: + return VectorGraphicDataType::Svg; + + default: + break; + } + return std::optional<VectorGraphicDataType>(); +} + +} // end namespace + +bool ImpGraphic::swapIn() +{ + if (!isSwappedOut()) + return false; + + bool bReturn = false; + + if (mbPrepared) + { + Graphic aGraphic; + if (!mpGfxLink->LoadNative(aGraphic)) + return false; + + updateFromLoadedGraphic(aGraphic.ImplGetImpGraphic()); + + maLastUsed = std::chrono::high_resolution_clock::now(); + bReturn = true; + } + else if (mpGfxLink && mpGfxLink->IsNative()) + { + std::optional<VectorGraphicDataType> oType = lclConvertToVectorGraphicType(*mpGfxLink); + if (oType) + { + maVectorGraphicData = vcl::loadVectorGraphic(mpGfxLink->getDataContainer(), *oType); + + // Set to 0, to force recalculation + mnSizeBytes = 0; + mnChecksum = 0; + + restoreFromSwapInfo(); + + mbSwapOut = false; + } + else + { + Graphic aGraphic; + if (!mpGfxLink->LoadNative(aGraphic)) + return false; + + ImpGraphic* pImpGraphic = aGraphic.ImplGetImpGraphic(); + if (meType != pImpGraphic->meType) + return false; + + updateFromLoadedGraphic(pImpGraphic); + } + + maLastUsed = std::chrono::high_resolution_clock::now(); + bReturn = true; + } + else + { + SvStream* pStream = nullptr; + + if (mpSwapFile) + pStream = mpSwapFile->getStream(); + + if (pStream) + { + pStream->SetVersion(SOFFICE_FILEFORMAT_50); + pStream->SetCompressMode(SvStreamCompressFlags::NATIVE); + pStream->SetBufferSize(GRAPHIC_STREAMBUFSIZE); + pStream->Seek(STREAM_SEEK_TO_BEGIN); + + bReturn = swapInFromStream(*pStream); + + restoreFromSwapInfo(); + + setOriginURL(mpSwapFile->getOriginURL()); + + mpSwapFile.reset(); + } + } + + if (bReturn) + { + vcl::graphic::Manager::get().swappedIn(this, getSizeBytes()); + } + + return bReturn; +} + +bool ImpGraphic::swapInFromStream(SvStream& rStream) +{ + bool bRet = false; + + if (rStream.GetError()) + return false; + + clearGraphics(); + mnSizeBytes = 0; + mnChecksum = 0; + + bRet = swapInContent(rStream); + + if (!bRet) + { + //throw away swapfile, etc. + clear(); + } + + mbSwapOut = false; + + return bRet; +} + +bool ImpGraphic::swapInGraphic(SvStream& rStream) +{ + bool bReturn = false; + + if (rStream.GetError()) + return bReturn; + + if (meType == GraphicType::Bitmap) + { + sal_Int32 nContentType = -1; + rStream.ReadInt32(nContentType); + if (nContentType < 0) + return false; + + auto eContentType = static_cast<GraphicContentType>(nContentType); + + switch (eContentType) + { + case GraphicContentType::Bitmap: + { + BitmapEx aBitmapEx; + ReadDIBBitmapEx(aBitmapEx, rStream); + if (!rStream.GetError()) + { + maBitmapEx = aBitmapEx; + bReturn = true; + } + } + break; + + case GraphicContentType::Animation: + { + auto pAnimation = std::make_unique<Animation>(); + ReadAnimation(rStream, *pAnimation); + if (!rStream.GetError()) + { + mpAnimation = std::move(pAnimation); + maBitmapEx = mpAnimation->GetBitmapEx(); + bReturn = true; + } + } + break; + + case GraphicContentType::Vector: + { + // try to stream in Svg defining data (length, byte array and evtl. path) + // See below (operator<<) for more information + sal_uInt32 nMagic; + rStream.ReadUInt32(nMagic); + + if (constSvgMagic == nMagic || constWmfMagic == nMagic || constEmfMagic == nMagic || constPdfMagic == nMagic) + { + sal_uInt32 nVectorGraphicDataSize(0); + rStream.ReadUInt32(nVectorGraphicDataSize); + + if (nVectorGraphicDataSize) + { + BinaryDataContainer aDataContainer(rStream, nVectorGraphicDataSize); + + if (rStream.GetError()) + return false; + + VectorGraphicDataType aDataType; + + switch (nMagic) + { + case constSvgMagic: + aDataType = VectorGraphicDataType::Svg; + break; + case constWmfMagic: + aDataType = VectorGraphicDataType::Wmf; + break; + case constEmfMagic: + aDataType = VectorGraphicDataType::Emf; + break; + case constPdfMagic: + aDataType = VectorGraphicDataType::Pdf; + break; + default: + return false; + } + + auto aVectorGraphicDataPtr = std::make_shared<VectorGraphicData>(aDataContainer, aDataType); + + if (!rStream.GetError()) + { + maVectorGraphicData = aVectorGraphicDataPtr; + bReturn = true; + } + } + } + } + break; + } + } + else if (meType == GraphicType::GdiMetafile) + { + GDIMetaFile aMetaFile; + SvmReader aReader(rStream); + aReader.Read(aMetaFile); + if (!rStream.GetError()) + { + maMetaFile = aMetaFile; + bReturn = true; + } + } + return bReturn; +} + +void ImpGraphic::setGfxLink(const std::shared_ptr<GfxLink>& rGfxLink) +{ + ensureAvailable(); + + mpGfxLink = rGfxLink; +} + +const std::shared_ptr<GfxLink> & ImpGraphic::getSharedGfxLink() const +{ + return mpGfxLink; +} + +GfxLink ImpGraphic::getGfxLink() const +{ + ensureAvailable(); + + return( mpGfxLink ? *mpGfxLink : GfxLink() ); +} + +bool ImpGraphic::isGfxLink() const +{ + return ( bool(mpGfxLink) ); +} + +BitmapChecksum ImpGraphic::getChecksum() const +{ + if (mnChecksum != 0) + return mnChecksum; + + ensureAvailable(); + + switch (meType) + { + case GraphicType::NONE: + case GraphicType::Default: + break; + + case GraphicType::Bitmap: + { + if (maVectorGraphicData) + mnChecksum = maVectorGraphicData->GetChecksum(); + else if (mpAnimation) + mnChecksum = mpAnimation->GetChecksum(); + else + mnChecksum = maBitmapEx.GetChecksum(); + } + break; + + case GraphicType::GdiMetafile: + { + mnChecksum = SvmWriter::GetChecksum(maMetaFile); + } + break; + } + return mnChecksum; +} + +sal_Int32 ImpGraphic::getPageNumber() const +{ + if (isSwappedOut()) + return maSwapInfo.mnPageIndex; + + if (maVectorGraphicData) + return maVectorGraphicData->getPageIndex(); + return -1; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |