diff options
author | Armin Le Grand <Armin.Le.Grand@cib.de> | 2017-06-16 17:16:22 +0200 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2017-07-15 11:01:30 +0200 |
commit | 783269e91e2166357a9fb095e64a1d48e6f0601a (patch) | |
tree | a91bb0d9ee76564ed44415b62a606da7f0d24a8a | |
parent | cfe47d035822ab4a46e1d34e26e383a45b9adddd (diff) |
emfplus: completed isolation/migration of Emf/Wmf
Decided to keep the migrated/isolated Emf/Wmf reader
which are now hidden behind a Uno Api. Had to re-implement
WMF_EXTERNALHEADER (now WmfExternal, own file/header)
to not break anything. It *seems* to just scale something
and could be done after import, but I could not be sure.
Also needed a callback hook to allow getting the Metafile
out of a MetafilePrimitive in a lower module (vcl relative
to drawinglayer) which is needed as long as primitives
are not completely on Uno Api. Deleted all Emf/Wmf reader
stuff from vcl.
Change-Id: Ic5540defa8ec770728280df4df3f12e1f48cfc3a
31 files changed, 422 insertions, 7038 deletions
diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx index e07033aa50d5..4737f78c765b 100644 --- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx @@ -3244,6 +3244,13 @@ namespace drawinglayer return aRetval; } + // from MetafileAccessor + bool MetafilePrimitive2D::accessMetafile(GDIMetaFile& rTargetMetafile) const + { + rTargetMetafile = maMetaFile; + return true; + } + // provide unique ID ImplPrimitive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D) diff --git a/emfio/inc/mtftools.hxx b/emfio/inc/mtftools.hxx index e2dc6830e1dd..7442a3111f04 100644 --- a/emfio/inc/mtftools.hxx +++ b/emfio/inc/mtftools.hxx @@ -593,13 +593,13 @@ namespace emfio const Point& rStartAngle, const Point& rEndAngle ); - void DrawPolygon(tools::Polygon& rPolygon, bool bRecordPath); + void DrawPolygon(tools::Polygon rPolygon, bool bRecordPath); void DrawPolyPolygon(tools::PolyPolygon& rPolyPolygon, bool bRecordPath = false); - void DrawPolyLine(tools::Polygon& rPolygon, + void DrawPolyLine(tools::Polygon rPolygon, bool bDrawTo = false, bool bRecordPath = false ); - void DrawPolyBezier(tools::Polygon& rPolygin, + void DrawPolyBezier(tools::Polygon rPolygin, bool bDrawTo, bool bRecordPath ); diff --git a/emfio/inc/wmfreader.hxx b/emfio/inc/wmfreader.hxx index e0566bb95cfb..1cd6077b05d8 100644 --- a/emfio/inc/wmfreader.hxx +++ b/emfio/inc/wmfreader.hxx @@ -23,6 +23,9 @@ #include <mtftools.hxx> #include <tools/stream.hxx> +// predefines +struct WmfExternal; + namespace emfio { class WmfReader : public MtfTools @@ -46,6 +49,9 @@ namespace emfio sal_uInt32 mnSkipActions; sal_uInt32 mnCurrentAction; + // eventually handed over external header + const WmfExternal* mpExternalHeader; + // reads header of the WMF-Datei bool ReadHeader(); @@ -59,7 +65,7 @@ namespace emfio void GetPlaceableBound(tools::Rectangle& rSize, SvStream* pStrm); public: - WmfReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile); + WmfReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, const WmfExternal* pExternalHeader); // read WMF file from stream and fill the GDIMetaFile void ReadWMF(); diff --git a/emfio/source/emfuno/xemfparser.cxx b/emfio/source/emfuno/xemfparser.cxx index 89d34dff1521..433210c5ecd2 100644 --- a/emfio/source/emfuno/xemfparser.cxx +++ b/emfio/source/emfuno/xemfparser.cxx @@ -33,7 +33,6 @@ #include <vcl/svapp.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> -#include <vcl/wmf.hxx> #include <unotools/ucbstreamhelper.hxx> #include <drawinglayer/primitive2d/metafileprimitive2d.hxx> @@ -69,7 +68,8 @@ namespace emfio // XEmfParser virtual uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > SAL_CALL getDecomposition( const uno::Reference< ::io::XInputStream >& xEmfStream, - const OUString& aAbsolutePath) override; + const OUString& aAbsolutePath, + const uno::Sequence< ::beans::PropertyValue >& rProperties) override; // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; @@ -113,114 +113,85 @@ namespace emfio uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > XEmfParser::getDecomposition( const uno::Reference< ::io::XInputStream >& xEmfStream, - const OUString& aAbsolutePath ) + const OUString& aAbsolutePath, + const uno::Sequence< ::beans::PropertyValue >& rProperties) { drawinglayer::primitive2d::Primitive2DContainer aRetval; if (xEmfStream.is()) { - static bool bTestCode(false); + WmfExternal aExternalHeader; + const bool bExternalHeaderUsed(aExternalHeader.setSequence(rProperties)); - if (bTestCode) + // rough check - import and conv to primitive + GDIMetaFile aMtf; + std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xEmfStream)); + sal_uInt32 nMetaType(0); + sal_uInt32 nOrgPos = pStream->Tell(); + + SvStreamEndian nOrigNumberFormat = pStream->GetEndian(); + pStream->SetEndian(SvStreamEndian::LITTLE); + + pStream->Seek(0x28); + pStream->ReadUInt32(nMetaType); + pStream->Seek(nOrgPos); + + if (nMetaType == 0x464d4520) + { + emfio::EmfReader(*pStream, aMtf).ReadEnhWMF(); + } + else + { + emfio::WmfReader(*pStream, aMtf, bExternalHeaderUsed ? &aExternalHeader : nullptr).ReadWMF(); + } + + pStream->SetEndian(nOrigNumberFormat); + Size aSize(aMtf.GetPrefSize()); + + if (aMtf.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel) { - static bool bUseOldFilterEmbedded(true); - - if (bUseOldFilterEmbedded) - { - GDIMetaFile aMtf; - std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xEmfStream)); - - if (pStream && ConvertWMFToGDIMetaFile(*pStream, aMtf, nullptr, nullptr)) - { - - Size aSize(aMtf.GetPrefSize()); - - if (aMtf.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel) - { - aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, MapUnit::Map100thMM); - } - else - { - aSize = OutputDevice::LogicToLogic(aSize, aMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)); - } - - const basegfx::B2DHomMatrix aMetafileTransform( - basegfx::tools::createScaleB2DHomMatrix( - aSize.Width(), - aSize.Height())); - - aRetval.push_back( - new drawinglayer::primitive2d::MetafilePrimitive2D( - aMetafileTransform, - aMtf)); - } - } - - if(aRetval.empty()) - { - // for test, just create some graphic data that will get visualized - const basegfx::B2DRange aRange(1000, 1000, 5000, 5000); - const basegfx::BColor aColor(1.0, 0.0, 0.0); - const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); - - aRetval.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aColor)); - } + aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, MapUnit::Map100thMM); } else { - // new parser here - bool bBla = true; - - // rouch check - import and conv to primitive - GDIMetaFile aMtf; - std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream(xEmfStream)); - sal_uInt32 nMetaType(0); - sal_uInt32 nOrgPos = pStream->Tell(); - - SvStreamEndian nOrigNumberFormat = pStream->GetEndian(); - pStream->SetEndian(SvStreamEndian::LITTLE); - - pStream->Seek(0x28); - pStream->ReadUInt32(nMetaType); - pStream->Seek(nOrgPos); - - if (nMetaType == 0x464d4520) - { - emfio::EmfReader(*pStream, aMtf).ReadEnhWMF(); - } - else - { - emfio::WmfReader(*pStream, aMtf).ReadWMF(); - } - - pStream->SetEndian(nOrigNumberFormat); - Size aSize(aMtf.GetPrefSize()); - - if (aMtf.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel) - { - aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, MapUnit::Map100thMM); - } - else - { - aSize = OutputDevice::LogicToLogic(aSize, aMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)); - } - - const basegfx::B2DHomMatrix aMetafileTransform( - basegfx::tools::createScaleB2DHomMatrix( - aSize.Width(), - aSize.Height())); - - // force to use decomposition directly to get rid of the metafile - const css::uno::Sequence< css::beans::PropertyValue > aViewParameters; - drawinglayer::primitive2d::MetafilePrimitive2D aMetafilePrimitive2D( + aSize = OutputDevice::LogicToLogic(aSize, aMtf.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)); + } + + // use size + const basegfx::B2DHomMatrix aMetafileTransform( + basegfx::tools::createScaleB2DHomMatrix( + aSize.Width(), + aSize.Height())); + + // ...and create a single MetafilePrimitive2D containing the Metafile. + // CAUTION: Currently, ReadWindowMetafile uses the local VectorGraphicData + // and a MetafileAccessor hook at the MetafilePrimitive2D inside of + // ImpGraphic::ImplGetGDIMetaFile to get the Metafile. Thus, the first + // and only primitive in this case *has to be* a MetafilePrimitive2D. + aRetval.push_back( + new drawinglayer::primitive2d::MetafilePrimitive2D( aMetafileTransform, - aMtf); - aRetval.append(aMetafilePrimitive2D.getDecomposition(aViewParameters)); + aMtf)); + // // force to use decomposition directly to get rid of the metafile + // const css::uno::Sequence< css::beans::PropertyValue > aViewParameters; + // drawinglayer::primitive2d::MetafilePrimitive2D aMetafilePrimitive2D( + // aMetafileTransform, + // aMtf); + // aRetval.append(aMetafilePrimitive2D.getDecomposition(aViewParameters)); + + // if (aRetval.empty()) + // { + // // for test, just create some graphic data that will get visualized + // const basegfx::B2DRange aRange(1000, 1000, 5000, 5000); + // const basegfx::BColor aColor(1.0, 0.0, 0.0); + // const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange)); + // + // aRetval.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aOutline), aColor)); + // } - } } else { diff --git a/emfio/source/reader/mtftools.cxx b/emfio/source/reader/mtftools.cxx index 96d4d5232e7e..7c2938730b42 100644 --- a/emfio/source/reader/mtftools.cxx +++ b/emfio/source/reader/mtftools.cxx @@ -20,13 +20,10 @@ #include <mtftools.hxx> #include <memory> -//#include "winmtf.hxx" #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/polygon/b2dpolypolygontools.hxx> -//#include <vcl/metaact.hxx> #include <vcl/graphictools.hxx> #include <vcl/canvastools.hxx> -//#include <vcl/metric.hxx> #include <vcl/svapp.hxx> #include <tools/fract.hxx> #include <rtl/strbuf.hxx> @@ -1249,7 +1246,7 @@ namespace emfio } } - void MtfTools::DrawPolygon( tools::Polygon& rPolygon, bool bRecordPath ) + void MtfTools::DrawPolygon( tools::Polygon rPolygon, bool bRecordPath ) { UpdateClipRegion(); ImplMap( rPolygon ); @@ -1354,7 +1351,7 @@ namespace emfio } } - void MtfTools::DrawPolyLine( tools::Polygon& rPolygon, bool bTo, bool bRecordPath ) + void MtfTools::DrawPolyLine( tools::Polygon rPolygon, bool bTo, bool bRecordPath ) { UpdateClipRegion(); @@ -1377,7 +1374,7 @@ namespace emfio } } - void MtfTools::DrawPolyBezier( tools::Polygon& rPolygon, bool bTo, bool bRecordPath ) + void MtfTools::DrawPolyBezier( tools::Polygon rPolygon, bool bTo, bool bRecordPath ) { sal_uInt16 nPoints = rPolygon.GetSize(); if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) ) diff --git a/emfio/source/reader/wmfreader.cxx b/emfio/source/reader/wmfreader.cxx index 3784153b1499..d71e234826d9 100644 --- a/emfio/source/reader/wmfreader.cxx +++ b/emfio/source/reader/wmfreader.cxx @@ -1242,26 +1242,45 @@ namespace emfio { mnUnitsPerInch = 96; + if (mpExternalHeader != nullptr + && mpExternalHeader->xExt > 0 + && mpExternalHeader->yExt > 0 + && (mpExternalHeader->mapMode == MM_ISOTROPIC || mpExternalHeader->mapMode == MM_ANISOTROPIC)) + { + // #n417818#: If we have an external header then overwrite the bounds! + tools::Rectangle aExtRect(0, 0, + (double)mpExternalHeader->xExt * 567 * mnUnitsPerInch / 1440000, + (double)mpExternalHeader->yExt * 567 * mnUnitsPerInch / 1440000); + aPlaceableBound = aExtRect; + + SAL_INFO("vcl.wmf", "External header size " + " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top() + << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom()); - mpInputStream->Seek( nStrmPos + 18 ); // set the streampos to the start of the metaactions - GetPlaceableBound( aPlaceableBound, mpInputStream ); - - // The image size is not known so normalize the calculated bounds so that the - // resulting image is not too big - const double fMaxWidth = static_cast<double>(aMaxWidth); - if (aPlaceableBound.GetWidth() > aMaxWidth) + SetMapMode(mpExternalHeader->mapMode); + } + else { - double fRatio = aPlaceableBound.GetWidth() / fMaxWidth; + mpInputStream->Seek(nStrmPos + 18); // set the streampos to the start of the metaactions + GetPlaceableBound(aPlaceableBound, mpInputStream); - aPlaceableBound = tools::Rectangle( - aPlaceableBound.Left() / fRatio, - aPlaceableBound.Top() / fRatio, - aPlaceableBound.Right() / fRatio, - aPlaceableBound.Bottom() / fRatio); + // The image size is not known so normalize the calculated bounds so that the + // resulting image is not too big + const double fMaxWidth = static_cast<double>(aMaxWidth); + if (aPlaceableBound.GetWidth() > aMaxWidth) + { + double fRatio = aPlaceableBound.GetWidth() / fMaxWidth; - SAL_INFO("vcl.wmf", "Placeable bounds " - " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top() - << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom()); + aPlaceableBound = tools::Rectangle( + aPlaceableBound.Left() / fRatio, + aPlaceableBound.Top() / fRatio, + aPlaceableBound.Right() / fRatio, + aPlaceableBound.Bottom() / fRatio); + + SAL_INFO("vcl.wmf", "Placeable bounds " + " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top() + << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom()); + } } mpInputStream->Seek( nStrmPos ); @@ -1800,7 +1819,7 @@ namespace emfio } } - WmfReader::WmfReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile) + WmfReader::WmfReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, const WmfExternal* pExternalHeader) : MtfTools(rGDIMetaFile, rStreamWMF) , mnUnitsPerInch(96) , mnRecSize(0) @@ -1810,6 +1829,7 @@ namespace emfio , mnEMFSize(0) , mnSkipActions(0) , mnCurrentAction(0) + , mpExternalHeader(pExternalHeader) { } } diff --git a/include/drawinglayer/primitive2d/metafileprimitive2d.hxx b/include/drawinglayer/primitive2d/metafileprimitive2d.hxx index 0d1503809a81..e849e38b5752 100644 --- a/include/drawinglayer/primitive2d/metafileprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/metafileprimitive2d.hxx @@ -25,6 +25,7 @@ #include <drawinglayer/primitive2d/baseprimitive2d.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <vcl/gdimtf.hxx> +#include <vcl/gdimetafiletools.hxx> // MetafilePrimitive2D class @@ -53,7 +54,7 @@ namespace drawinglayer have many advantages; Metafile would no longer have to be rendered by sub-systems and a standard way for converting Metafiles would exist. */ - class DRAWINGLAYER_DLLPUBLIC MetafilePrimitive2D : public BufferedDecompositionPrimitive2D + class DRAWINGLAYER_DLLPUBLIC MetafilePrimitive2D : public BufferedDecompositionPrimitive2D, public MetafileAccessor { private: /// the geometry definition @@ -81,6 +82,9 @@ namespace drawinglayer /// get range virtual basegfx::B2DRange getB2DRange(const geometry::ViewInformation2D& rViewInformation) const override; + /// from MetafileAccessor + virtual bool accessMetafile(GDIMetaFile& rTargetMetafile) const; + /// provide unique ID DeclPrimitive2DIDBlock() }; diff --git a/include/oox/helper/graphichelper.hxx b/include/oox/helper/graphichelper.hxx index 651e9407b4ec..545bdd0fd938 100644 --- a/include/oox/helper/graphichelper.hxx +++ b/include/oox/helper/graphichelper.hxx @@ -33,7 +33,7 @@ #include <sal/types.h> #include <com/sun/star/graphic/XGraphicProvider2.hpp> -struct WMF_EXTERNALHEADER; +struct WmfExternal; namespace com { namespace sun { namespace star { namespace awt { struct Point; } @@ -113,7 +113,7 @@ public: css::uno::Reference< css::graphic::XGraphic > importGraphic( const css::uno::Reference< css::io::XInputStream >& rxInStrm, - const WMF_EXTERNALHEADER* pExtHeader = nullptr ) const; + const WmfExternal* pExtHeader = nullptr ) const; /** Imports graphics from the passed input streams. */ std::vector< css::uno::Reference<css::graphic::XGraphic> > @@ -127,7 +127,7 @@ public: css::uno::Reference< css::graphic::XGraphic > importEmbeddedGraphic( const OUString& rStreamName, - const WMF_EXTERNALHEADER* pExtHeader = nullptr ) const; + const WmfExternal* pExtHeader = nullptr ) const; /** Imports graphics from the storage with the passed stream names. */ void importEmbeddedGraphics(const std::vector<OUString>& rStreamNames) const; @@ -141,7 +141,7 @@ public: @return The URL of the created and internally cached graphic object. */ OUString importGraphicObject( const css::uno::Reference< css::io::XInputStream >& rxInStrm, - const WMF_EXTERNALHEADER* pExtHeader ) const; + const WmfExternal* pExtHeader ) const; /** Creates a persistent graphic object from the passed binary memory block. @return The URL of the created and internally cached graphic object. */ diff --git a/include/vcl/gdimetafiletools.hxx b/include/vcl/gdimetafiletools.hxx index 592c70714bfd..ea47ced5032e 100644 --- a/include/vcl/gdimetafiletools.hxx +++ b/include/vcl/gdimetafiletools.hxx @@ -39,6 +39,15 @@ void VCL_DLLPUBLIC clipMetafileContentAgainstOwnRegions(GDIMetaFile& rSource); bool VCL_DLLPUBLIC usesClipActions(const GDIMetaFile& rSource); +// hook to access metafile members in classes of modules above vcl. Currently +// used in MetafilePrimitive2D to be able to access the local Metafile member +// e.g. from vcl module +class VCL_DLLPUBLIC MetafileAccessor +{ +public: + virtual bool accessMetafile(GDIMetaFile& rTargetMetafile) const = 0; +}; + #endif // INCLUDED_VCL_GDIMETAFILETOOLS_HXX diff --git a/include/vcl/graphicfilter.hxx b/include/vcl/graphicfilter.hxx index d67237975ae1..deed307298cf 100644 --- a/include/vcl/graphicfilter.hxx +++ b/include/vcl/graphicfilter.hxx @@ -33,7 +33,7 @@ class FilterConfigCache; class SvStream; -struct WMF_EXTERNALHEADER; +struct WmfExternal; struct ConvertData; #define ERRCODE_GRFILTER_OPENERROR ErrCode(ERRCODE_AREA_VCL | ERRCODE_CLASS_GENERAL | 1) @@ -279,7 +279,7 @@ public: SvStream& rStream, sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, sal_uInt16 * pDeterminedFormat = nullptr, GraphicFilterImportFlags nImportFlags = GraphicFilterImportFlags::NONE, - WMF_EXTERNALHEADER *pExtHeader = nullptr ); + WmfExternal *pExtHeader = nullptr ); /// Imports multiple graphics. /// @@ -291,7 +291,7 @@ public: sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, GraphicFilterImportFlags nImportFlags, css::uno::Sequence< css::beans::PropertyValue >* pFilterData, - WMF_EXTERNALHEADER *pExtHeader = nullptr ); + WmfExternal *pExtHeader = nullptr ); const FilterErrorEx& GetLastError() const { return *pErrorEx;} void ResetLastError(); diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx index 6a259a5567e3..a045b01ee46e 100644 --- a/include/vcl/vectorgraphicdata.hxx +++ b/include/vcl/vectorgraphicdata.hxx @@ -23,6 +23,7 @@ #include <basegfx/range/b2drange.hxx> #include <com/sun/star/graphic/XPrimitive2D.hpp> #include <vcl/bitmapex.hxx> +#include <vcl/wmfexternal.hxx> #include <rtl/ustring.hxx> #include <deque> @@ -57,12 +58,14 @@ private: // on demand created content basegfx::B2DRange maRange; - std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > - maSequence; + std::deque< css::uno::Reference< css::graphic::XPrimitive2D > > maSequence; BitmapEx maReplacement; size_t mNestedBitmapSize; VectorGraphicDataType meVectorGraphicDataType; + // extra: + WmfExternal* mpExternalHeader; + // on demand creators void ensureReplacement(); void ensureSequenceAndRange(); @@ -78,10 +81,14 @@ public: VectorGraphicData( const OUString& rPath, VectorGraphicDataType eVectorDataType); + ~VectorGraphicData(); /// compare op bool operator==(const VectorGraphicData& rCandidate) const; + /// special: needed for emf/wmf, maybe replaced by scaling the result later (?) + void setWmfExternalHeader(const WmfExternal& aExtHeader); + /// data read const VectorGraphicDataArray& getVectorGraphicDataArray() const { return maVectorGraphicDataArray; } sal_uInt32 getVectorGraphicDataArrayLength() const { return maVectorGraphicDataArray.getLength(); } diff --git a/include/vcl/wmf.hxx b/include/vcl/wmf.hxx index 67d6aa4f122b..c172cd45e86b 100644 --- a/include/vcl/wmf.hxx +++ b/include/vcl/wmf.hxx @@ -25,38 +25,7 @@ class FilterConfigItem; class GDIMetaFile; class SvStream; - -struct WMF_EXTERNALHEADER -{ - sal_uInt16 xExt; - sal_uInt16 yExt; - - /** One of the following values: - <ul> - <li>MM_TEXT</li> - <li>MM_LOMETRIC</li> - <li>MM_HIMETRIC</li> - <li>MM_LOENGLISH</li> - <li>MM_HIENGLISH</li> - <li>MM_TWIPS</li> - <li>MM_ISOTROPIC</li> - <li>MM_ANISOTROPIC</li> - </ul> - If this value is 0, then no external mapmode has been defined, - the internal one should then be used. - */ - sal_uInt16 mapMode; - - WMF_EXTERNALHEADER() : - xExt( 0 ), - yExt( 0 ), - mapMode( 0 ) - { - } -}; - -// for 1st test, export -VCL_DLLPUBLIC bool ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER *pExtHeader ); +struct WmfExternal; VCL_DLLPUBLIC bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF ); diff --git a/include/vcl/wmfexternal.hxx b/include/vcl/wmfexternal.hxx new file mode 100644 index 000000000000..fd55c621c060 --- /dev/null +++ b/include/vcl/wmfexternal.hxx @@ -0,0 +1,56 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_VCL_WMFEXTERNAL_HXX +#define INCLUDED_VCL_WMFEXTERNAL_HXX + +#include <vcl/dllapi.h> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> + +struct VCL_DLLPUBLIC WmfExternal +{ + sal_uInt16 xExt; + sal_uInt16 yExt; + + /** One of the following values: + <ul> + <li>MM_TEXT</li> + <li>MM_LOMETRIC</li> + <li>MM_HIMETRIC</li> + <li>MM_LOENGLISH</li> + <li>MM_HIENGLISH</li> + <li>MM_TWIPS</li> + <li>MM_ISOTROPIC</li> + <li>MM_ANISOTROPIC</li> + </ul> + If this value is 0, then no external mapmode has been defined, + the internal one should then be used. + */ + sal_uInt16 mapMode; + + WmfExternal(); + css::uno::Sequence< css::beans::PropertyValue > getSequence() const; + bool setSequence(const css::uno::Sequence< css::beans::PropertyValue >& rSequence); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/offapi/com/sun/star/graphic/XEmfParser.idl b/offapi/com/sun/star/graphic/XEmfParser.idl index 6c55a8a0b963..42cb2cbe6459 100644 --- a/offapi/com/sun/star/graphic/XEmfParser.idl +++ b/offapi/com/sun/star/graphic/XEmfParser.idl @@ -41,10 +41,14 @@ interface XEmfParser : ::com::sun::star::uno::XInterface @param aAbsolutePath The path containing the WMF/EMF/EMF+ data - */ + + @param Properties + Optional values to override MapMode and size +*/ sequence< XPrimitive2D > getDecomposition( [in] io::XInputStream xEmfStream, - [in] string aAbsolutePath); + [in] string aAbsolutePath, + [in] ::com::sun::star::beans::PropertyValues Properties); }; }; }; }; }; diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index a01fd47075d0..3368cd0c315a 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -1288,7 +1288,7 @@ OUString Shape::finalizeServiceName( XmlFilterBase& rFilter, const OUString& rSe if( !aGraphicPath.isEmpty() ) { // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF) - WMF_EXTERNALHEADER aExtHeader; + WmfExternal aExtHeader; aExtHeader.mapMode = 8; // MM_ANISOTROPIC aExtHeader.xExt = rShapeRect.Width; aExtHeader.yExt = rShapeRect.Height; diff --git a/oox/source/helper/graphichelper.cxx b/oox/source/helper/graphichelper.cxx index fb114290f25b..abd58b2a065e 100644 --- a/oox/source/helper/graphichelper.cxx +++ b/oox/source/helper/graphichelper.cxx @@ -233,7 +233,7 @@ awt::Size GraphicHelper::convertHmmToAppFont( const awt::Size& rHmm ) const // Graphics and graphic objects ---------------------------------------------- Reference< XGraphic > GraphicHelper::importGraphic( const Reference< XInputStream >& rxInStrm, - const WMF_EXTERNALHEADER* pExtHeader ) const + const WmfExternal* pExtHeader ) const { Reference< XGraphic > xGraphic; if( rxInStrm.is() && mxGraphicProvider.is() ) try @@ -330,7 +330,7 @@ void GraphicHelper::importEmbeddedGraphics(const std::vector<OUString>& rStreamN } } -Reference< XGraphic > GraphicHelper::importEmbeddedGraphic( const OUString& rStreamName, const WMF_EXTERNALHEADER* pExtHeader ) const +Reference< XGraphic > GraphicHelper::importEmbeddedGraphic( const OUString& rStreamName, const WmfExternal* pExtHeader ) const { Reference< XGraphic > xGraphic; OSL_ENSURE( !rStreamName.isEmpty(), "GraphicHelper::importEmbeddedGraphic - empty stream name" ); @@ -366,7 +366,7 @@ OUString GraphicHelper::createGraphicObject( const Reference< XGraphic >& rxGrap } OUString GraphicHelper::importGraphicObject( const Reference< XInputStream >& rxInStrm, - const WMF_EXTERNALHEADER* pExtHeader ) const + const WmfExternal* pExtHeader ) const { return createGraphicObject( importGraphic( rxInStrm, pExtHeader ) ); } diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index f091326e0c1e..b0dda2a6a134 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -1163,7 +1163,7 @@ Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes // set the replacement graphic if( !aGraphicPath.isEmpty() ) { - WMF_EXTERNALHEADER aExtHeader; + WmfExternal aExtHeader; aExtHeader.mapMode = 8; aExtHeader.xExt = rShapeRect.Width; aExtHeader.yExt = rShapeRect.Height; diff --git a/svtools/source/graphic/provider.cxx b/svtools/source/graphic/provider.cxx index 6e3e7e930ed5..44dc8de4981b 100644 --- a/svtools/source/graphic/provider.cxx +++ b/svtools/source/graphic/provider.cxx @@ -412,11 +412,11 @@ uno::Reference< ::graphic::XGraphic > SAL_CALL GraphicProvider::queryGraphic( co ::Graphic aVCLGraphic; // Define APM Header if goal height and width are defined - WMF_EXTERNALHEADER aExtHeader; + WmfExternal aExtHeader; aExtHeader.xExt = nExtWidth; aExtHeader.yExt = nExtHeight; aExtHeader.mapMode = nExtMapMode; - WMF_EXTERNALHEADER *pExtHeader = nullptr; + WmfExternal *pExtHeader = nullptr; if ( nExtMapMode > 0 ) pExtHeader = &aExtHeader; diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 9735c606a1a8..2ad89aced588 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -373,10 +373,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/filter/jpeg/JpegWriter \ vcl/source/filter/jpeg/JpegTransform \ vcl/source/filter/wmf/emfwr \ - vcl/source/filter/wmf/enhwmf \ - vcl/source/filter/wmf/winmtf \ - vcl/source/filter/wmf/winwmf \ vcl/source/filter/wmf/wmf \ + vcl/source/filter/wmf/wmfexternal \ vcl/source/filter/wmf/wmfwr \ vcl/source/font/PhysicalFontCollection \ vcl/source/font/PhysicalFontFace \ diff --git a/vcl/qa/cppunit/wmf/wmfimporttest.cxx b/vcl/qa/cppunit/wmf/wmfimporttest.cxx index 4b9c46d51471..96e11c0984d2 100644 --- a/vcl/qa/cppunit/wmf/wmfimporttest.cxx +++ b/vcl/qa/cppunit/wmf/wmfimporttest.cxx @@ -23,7 +23,6 @@ #include <unotest/bootstrapfixturebase.hxx> #include <vcl/wmf.hxx> #include <vcl/metaact.hxx> -#include <winmtf.hxx> using namespace css; diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx index a436999af548..a0f9d21f9cca 100644 --- a/vcl/source/filter/graphicfilter.cxx +++ b/vcl/source/filter/graphicfilter.cxx @@ -1306,8 +1306,14 @@ ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const INetURLObject& rP return nRetValue; } -ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream, - sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags, WMF_EXTERNALHEADER *pExtHeader ) +ErrCode GraphicFilter::ImportGraphic( + Graphic& rGraphic, + const OUString& rPath, + SvStream& rIStream, + sal_uInt16 nFormat, + sal_uInt16* pDeterminedFormat, + GraphicFilterImportFlags nImportFlags, + WmfExternal *pExtHeader) { return ImportGraphic( rGraphic, rPath, rIStream, nFormat, pDeterminedFormat, nImportFlags, nullptr, pExtHeader ); } @@ -1462,7 +1468,7 @@ void GraphicFilter::ImportGraphics(std::vector< std::shared_ptr<Graphic> >& rGra ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, SvStream& rIStream, sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, GraphicFilterImportFlags nImportFlags, css::uno::Sequence< css::beans::PropertyValue >* pFilterData, - WMF_EXTERNALHEADER *pExtHeader ) + WmfExternal *pExtHeader ) { OUString aFilterName; OUString aExternalFilterName; @@ -1766,52 +1772,46 @@ ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, else if( aFilterName.equalsIgnoreAsciiCase( IMP_WMF ) || aFilterName.equalsIgnoreAsciiCase( IMP_EMF ) ) { - static bool bCheckEmfWmf = true; - if (bCheckEmfWmf) - { - if (rGraphic.IsDummyContext()) - rGraphic.SetDummyContext(false); + // use new UNO API service, do not directly import but create a + // Graphic that contains the original data and decomposes to + // primitives on demand + if (rGraphic.IsDummyContext()) + rGraphic.SetDummyContext(false); - const sal_uInt32 nStreamPosition(rIStream.Tell()); - const sal_uInt32 nStreamLength(rIStream.Seek(STREAM_SEEK_TO_END) - nStreamPosition); - VectorGraphicDataArray aNewData(nStreamLength); - bool bOkay(false); + const sal_uInt32 nStreamPosition(rIStream.Tell()); + const sal_uInt32 nStreamLength(rIStream.Seek(STREAM_SEEK_TO_END) - nStreamPosition); + VectorGraphicDataArray aNewData(nStreamLength); + bool bOkay(false); - rIStream.Seek(nStreamPosition); - rIStream.ReadBytes(aNewData.begin(), nStreamLength); + rIStream.Seek(nStreamPosition); + rIStream.ReadBytes(aNewData.begin(), nStreamLength); - if (!rIStream.GetError()) + if (!rIStream.GetError()) + { + const bool bIsWmf(aFilterName.equalsIgnoreAsciiCase(IMP_WMF)); + const VectorGraphicDataType aDataType(bIsWmf ? VectorGraphicDataType::Wmf : VectorGraphicDataType::Emf); + VectorGraphicDataPtr aVectorGraphicDataPtr( + new VectorGraphicData( + aNewData, + rPath, + aDataType)); + + if (pExtHeader) { - const bool bIsWmf(aFilterName.equalsIgnoreAsciiCase(IMP_WMF)); - const VectorGraphicDataType aDataType(bIsWmf ? VectorGraphicDataType::Wmf : VectorGraphicDataType::Emf); - VectorGraphicDataPtr aVectorGraphicDataPtr( - new VectorGraphicData( - aNewData, - rPath, - aDataType)); - rGraphic = Graphic(aVectorGraphicDataPtr); - bOkay = true; + aVectorGraphicDataPtr->setWmfExternalHeader(*pExtHeader); } - if (bOkay) - { - eLinkType = GfxLinkType::NativeWmf; - } - else - { - nStatus = ERRCODE_GRFILTER_FILTERERROR; - } + rGraphic = Graphic(aVectorGraphicDataPtr); + bOkay = true; + } + + if (bOkay) + { + eLinkType = GfxLinkType::NativeWmf; } else { - GDIMetaFile aMtf; - if (!ConvertWMFToGDIMetaFile(rIStream, aMtf, nullptr, pExtHeader)) - nStatus = ERRCODE_GRFILTER_FORMATERROR; - else - { - rGraphic = aMtf; - eLinkType = GfxLinkType::NativeWmf; - } + nStatus = ERRCODE_GRFILTER_FILTERERROR; } } else if( aFilterName.equalsIgnoreAsciiCase( IMP_SVSGF ) diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx deleted file mode 100644 index 12ee4ddb86b6..000000000000 --- a/vcl/source/filter/wmf/enhwmf.cxx +++ /dev/null @@ -1,1967 +0,0 @@ -/* -*- 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 <osl/endian.h> -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <vcl/dibtools.hxx> -#include <o3tl/make_unique.hxx> - -#include "winmtf.hxx" - -#include <memory> - -#ifdef DBG_UTIL -#include <tools/stream.hxx> -#include <vcl/pngwrite.hxx> -#endif - -using namespace std; - -// GDI-Array - -#define EMR_HEADER 1 -#define EMR_POLYBEZIER 2 -#define EMR_POLYGON 3 -#define EMR_POLYLINE 4 -#define EMR_POLYBEZIERTO 5 -#define EMR_POLYLINETO 6 -#define EMR_POLYPOLYLINE 7 -#define EMR_POLYPOLYGON 8 -#define EMR_SETWINDOWEXTEX 9 -#define EMR_SETWINDOWORGEX 10 -#define EMR_SETVIEWPORTEXTEX 11 -#define EMR_SETVIEWPORTORGEX 12 -#define EMR_SETBRUSHORGEX 13 -#define EMR_EOF 14 -#define EMR_SETPIXELV 15 -#define EMR_SETMAPPERFLAGS 16 -#define EMR_SETMAPMODE 17 -#define EMR_SETBKMODE 18 -#define EMR_SETPOLYFILLMODE 19 -#define EMR_SETROP2 20 -#define EMR_SETSTRETCHBLTMODE 21 -#define EMR_SETTEXTALIGN 22 -#define EMR_SETCOLORADJUSTMENT 23 -#define EMR_SETTEXTCOLOR 24 -#define EMR_SETBKCOLOR 25 -#define EMR_OFFSETCLIPRGN 26 -#define EMR_MOVETOEX 27 -#define EMR_SETMETARGN 28 -#define EMR_EXCLUDECLIPRECT 29 -#define EMR_INTERSECTCLIPRECT 30 -#define EMR_SCALEVIEWPORTEXTEX 31 -#define EMR_SCALEWINDOWEXTEX 32 -#define EMR_SAVEDC 33 -#define EMR_RESTOREDC 34 -#define EMR_SETWORLDTRANSFORM 35 -#define EMR_MODIFYWORLDTRANSFORM 36 -#define EMR_SELECTOBJECT 37 -#define EMR_CREATEPEN 38 -#define EMR_CREATEBRUSHINDIRECT 39 -#define EMR_DELETEOBJECT 40 -#define EMR_ANGLEARC 41 -#define EMR_ELLIPSE 42 -#define EMR_RECTANGLE 43 -#define EMR_ROUNDRECT 44 -#define EMR_ARC 45 -#define EMR_CHORD 46 -#define EMR_PIE 47 -#define EMR_SELECTPALETTE 48 -#define EMR_CREATEPALETTE 49 -#define EMR_SETPALETTEENTRIES 50 -#define EMR_RESIZEPALETTE 51 -#define EMR_REALIZEPALETTE 52 -#define EMR_EXTFLOODFILL 53 -#define EMR_LINETO 54 -#define EMR_ARCTO 55 -#define EMR_POLYDRAW 56 -#define EMR_SETARCDIRECTION 57 -#define EMR_SETMITERLIMIT 58 -#define EMR_BEGINPATH 59 -#define EMR_ENDPATH 60 -#define EMR_CLOSEFIGURE 61 -#define EMR_FILLPATH 62 -#define EMR_STROKEANDFILLPATH 63 -#define EMR_STROKEPATH 64 -#define EMR_FLATTENPATH 65 -#define EMR_WIDENPATH 66 -#define EMR_SELECTCLIPPATH 67 -#define EMR_ABORTPATH 68 - -#define EMR_COMMENT 70 // Contains arbitrary private data. -// Comment Identifiers: -#define EMR_COMMENT_EMFPLUS 0x2B464D45 // Contains embedded EMF+ records. -#define EMR_COMMENT_EMFSPOOL 0x00000000 // Contains embedded EMFSPOOL records. -#define EMR_COMMENT_PUBLIC 0x43494447 // Specify extensions to EMF processing. - -#define EMR_FILLRGN 71 -#define EMR_FRAMERGN 72 -#define EMR_INVERTRGN 73 -#define EMR_PAINTRGN 74 -#define EMR_EXTSELECTCLIPRGN 75 -#define EMR_BITBLT 76 -#define EMR_STRETCHBLT 77 -#define EMR_MASKBLT 78 -#define EMR_PLGBLT 79 -#define EMR_SETDIBITSTODEVICE 80 -#define EMR_STRETCHDIBITS 81 -#define EMR_EXTCREATEFONTINDIRECTW 82 -#define EMR_EXTTEXTOUTA 83 -#define EMR_EXTTEXTOUTW 84 -#define EMR_POLYBEZIER16 85 -#define EMR_POLYGON16 86 -#define EMR_POLYLINE16 87 -#define EMR_POLYBEZIERTO16 88 -#define EMR_POLYLINETO16 89 -#define EMR_POLYPOLYLINE16 90 -#define EMR_POLYPOLYGON16 91 -#define EMR_POLYDRAW16 92 -#define EMR_CREATEMONOBRUSH 93 -#define EMR_CREATEDIBPATTERNBRUSHPT 94 -#define EMR_EXTCREATEPEN 95 -#define EMR_POLYTEXTOUTA 96 -#define EMR_POLYTEXTOUTW 97 - -// WINDOWS VERSION >= 0x400 -#define EMR_SETICMMODE 98 -#define EMR_CREATECOLORSPACE 99 -#define EMR_SETCOLORSPACE 100 -#define EMR_DELETECOLORSPACE 101 -#define EMR_GLSRECORD 102 -#define EMR_GLSBOUNDEDRECORD 103 -#define EMR_PIXELFORMAT 104 - -// WINDOWS VERSION >= 0x500 -#define EMR_DRAWESCAPE 105 -#define EMR_EXTESCAPE 106 -#define EMR_STARTDOC 107 -#define EMR_SMALLTEXTOUT 108 -#define EMR_FORCEUFIMAPPING 109 -#define EMR_NAMEDESCAPE 110 -#define EMR_COLORCORRECTPALETTE 111 -#define EMR_SETICMPROFILEA 112 -#define EMR_SETICMPROFILEW 113 -#define EMR_ALPHABLEND 114 -#define EMR_ALPHADIBBLEND 115 -#define EMR_TRANSPARENTBLT 116 -#define EMR_TRANSPARENTDIB 117 -#define EMR_GRADIENTFILL 118 -#define EMR_SETLINKEDUFIS 119 -#define EMR_SETTEXTJUSTIFICATION 120 - -namespace -{ - -const char * -record_type_name(sal_uInt32 nRecType) -{ -#ifndef SAL_LOG_INFO - (void) nRecType; - return ""; -#else - switch( nRecType ) - { - case EMR_HEADER: return "HEADER"; - case EMR_POLYBEZIER: return "POLYBEZIER"; - case EMR_POLYGON: return "POLYGON"; - case EMR_POLYLINE: return "POLYLINE"; - case EMR_POLYBEZIERTO: return "POLYBEZIERTO"; - case EMR_POLYLINETO: return "POLYLINETO"; - case EMR_POLYPOLYLINE: return "POLYPOLYLINE"; - case EMR_POLYPOLYGON: return "POLYPOLYGON"; - case EMR_SETWINDOWEXTEX: return "SETWINDOWEXTEX"; - case EMR_SETWINDOWORGEX: return "SETWINDOWORGEX"; - case EMR_SETVIEWPORTEXTEX: return "SETVIEWPORTEXTEX"; - case EMR_SETVIEWPORTORGEX: return "SETVIEWPORTORGEX"; - case EMR_SETBRUSHORGEX: return "SETBRUSHORGEX"; - case EMR_EOF: return "EOF"; - case EMR_SETPIXELV: return "SETPIXELV"; - case EMR_SETMAPPERFLAGS: return "SETMAPPERFLAGS"; - case EMR_SETMAPMODE: return "SETMAPMODE"; - case EMR_SETBKMODE: return "SETBKMODE"; - case EMR_SETPOLYFILLMODE: return "SETPOLYFILLMODE"; - case EMR_SETROP2: return "SETROP2"; - case EMR_SETSTRETCHBLTMODE: return "SETSTRETCHBLTMODE"; - case EMR_SETTEXTALIGN: return "SETTEXTALIGN"; - case EMR_SETCOLORADJUSTMENT: return "SETCOLORADJUSTMENT"; - case EMR_SETTEXTCOLOR: return "SETTEXTCOLOR"; - case EMR_SETBKCOLOR: return "SETBKCOLOR"; - case EMR_OFFSETCLIPRGN: return "OFFSETCLIPRGN"; - case EMR_MOVETOEX: return "MOVETOEX"; - case EMR_SETMETARGN: return "SETMETARGN"; - case EMR_EXCLUDECLIPRECT: return "EXCLUDECLIPRECT"; - case EMR_INTERSECTCLIPRECT: return "INTERSECTCLIPRECT"; - case EMR_SCALEVIEWPORTEXTEX: return "SCALEVIEWPORTEXTEX"; - case EMR_SCALEWINDOWEXTEX: return "SCALEWINDOWEXTEX"; - case EMR_SAVEDC: return "SAVEDC"; - case EMR_RESTOREDC: return "RESTOREDC"; - case EMR_SETWORLDTRANSFORM: return "SETWORLDTRANSFORM"; - case EMR_MODIFYWORLDTRANSFORM: return "MODIFYWORLDTRANSFORM"; - case EMR_SELECTOBJECT: return "SELECTOBJECT"; - case EMR_CREATEPEN: return "CREATEPEN"; - case EMR_CREATEBRUSHINDIRECT: return "CREATEBRUSHINDIRECT"; - case EMR_DELETEOBJECT: return "DELETEOBJECT"; - case EMR_ANGLEARC: return "ANGLEARC"; - case EMR_ELLIPSE: return "ELLIPSE"; - case EMR_RECTANGLE: return "RECTANGLE"; - case EMR_ROUNDRECT: return "ROUNDRECT"; - case EMR_ARC: return "ARC"; - case EMR_CHORD: return "CHORD"; - case EMR_PIE: return "PIE"; - case EMR_SELECTPALETTE: return "SELECTPALETTE"; - case EMR_CREATEPALETTE: return "CREATEPALETTE"; - case EMR_SETPALETTEENTRIES: return "SETPALETTEENTRIES"; - case EMR_RESIZEPALETTE: return "RESIZEPALETTE"; - case EMR_REALIZEPALETTE: return "REALIZEPALETTE"; - case EMR_EXTFLOODFILL: return "EXTFLOODFILL"; - case EMR_LINETO: return "LINETO"; - case EMR_ARCTO: return "ARCTO"; - case EMR_POLYDRAW: return "POLYDRAW"; - case EMR_SETARCDIRECTION: return "SETARCDIRECTION"; - case EMR_SETMITERLIMIT: return "SETMITERLIMIT"; - case EMR_BEGINPATH: return "BEGINPATH"; - case EMR_ENDPATH: return "ENDPATH"; - case EMR_CLOSEFIGURE: return "CLOSEFIGURE"; - case EMR_FILLPATH: return "FILLPATH"; - case EMR_STROKEANDFILLPATH: return "STROKEANDFILLPATH"; - case EMR_STROKEPATH: return "STROKEPATH"; - case EMR_FLATTENPATH: return "FLATTENPATH"; - case EMR_WIDENPATH: return "WIDENPATH"; - case EMR_SELECTCLIPPATH: return "SELECTCLIPPATH"; - case EMR_ABORTPATH: return "ABORTPATH"; - case EMR_COMMENT: return "COMMENT"; - case EMR_FILLRGN: return "FILLRGN"; - case EMR_FRAMERGN: return "FRAMERGN"; - case EMR_INVERTRGN: return "INVERTRGN"; - case EMR_PAINTRGN: return "PAINTRGN"; - case EMR_EXTSELECTCLIPRGN: return "EXTSELECTCLIPRGN"; - case EMR_BITBLT: return "BITBLT"; - case EMR_STRETCHBLT: return "STRETCHBLT"; - case EMR_MASKBLT: return "MASKBLT"; - case EMR_PLGBLT: return "PLGBLT"; - case EMR_SETDIBITSTODEVICE: return "SETDIBITSTODEVICE"; - case EMR_STRETCHDIBITS: return "STRETCHDIBITS"; - case EMR_EXTCREATEFONTINDIRECTW: return "EXTCREATEFONTINDIRECTW"; - case EMR_EXTTEXTOUTA: return "EXTTEXTOUTA"; - case EMR_EXTTEXTOUTW: return "EXTTEXTOUTW"; - case EMR_POLYBEZIER16: return "POLYBEZIER16"; - case EMR_POLYGON16: return "POLYGON16"; - case EMR_POLYLINE16: return "POLYLINE16"; - case EMR_POLYBEZIERTO16: return "POLYBEZIERTO16"; - case EMR_POLYLINETO16: return "POLYLINETO16"; - case EMR_POLYPOLYLINE16: return "POLYPOLYLINE16"; - case EMR_POLYPOLYGON16: return "POLYPOLYGON16"; - case EMR_POLYDRAW16: return "POLYDRAW16"; - case EMR_CREATEMONOBRUSH: return "CREATEMONOBRUSH"; - case EMR_CREATEDIBPATTERNBRUSHPT: return "CREATEDIBPATTERNBRUSHPT"; - case EMR_EXTCREATEPEN: return "EXTCREATEPEN"; - case EMR_POLYTEXTOUTA: return "POLYTEXTOUTA"; - case EMR_POLYTEXTOUTW: return "POLYTEXTOUTW"; - case EMR_SETICMMODE: return "SETICMMODE"; - case EMR_CREATECOLORSPACE: return "CREATECOLORSPACE"; - case EMR_SETCOLORSPACE: return "SETCOLORSPACE"; - case EMR_DELETECOLORSPACE: return "DELETECOLORSPACE"; - case EMR_GLSRECORD: return "GLSRECORD"; - case EMR_GLSBOUNDEDRECORD: return "GLSBOUNDEDRECORD"; - case EMR_PIXELFORMAT: return "PIXELFORMAT"; - case EMR_DRAWESCAPE: return "DRAWESCAPE"; - case EMR_EXTESCAPE: return "EXTESCAPE"; - case EMR_STARTDOC: return "STARTDOC"; - case EMR_SMALLTEXTOUT: return "SMALLTEXTOUT"; - case EMR_FORCEUFIMAPPING: return "FORCEUFIMAPPING"; - case EMR_NAMEDESCAPE: return "NAMEDESCAPE"; - case EMR_COLORCORRECTPALETTE: return "COLORCORRECTPALETTE"; - case EMR_SETICMPROFILEA: return "SETICMPROFILEA"; - case EMR_SETICMPROFILEW: return "SETICMPROFILEW"; - case EMR_ALPHABLEND: return "ALPHABLEND"; - case EMR_ALPHADIBBLEND: return "ALPHADIBBLEND"; - case EMR_TRANSPARENTBLT: return "TRANSPARENTBLT"; - case EMR_TRANSPARENTDIB: return "TRANSPARENTDIB"; - case EMR_GRADIENTFILL: return "GRADIENTFILL"; - case EMR_SETLINKEDUFIS: return "SETLINKEDUFIS"; - case EMR_SETTEXTJUSTIFICATION: return "SETTEXTJUSTIFICATION"; - default: - // Yes, return a pointer to a static buffer. This is a very - // local debugging output function, so no big deal. - static char buffer[11]; - sprintf(buffer, "0x%08" SAL_PRIxUINT32, nRecType); - return buffer; - } -#endif -} - -#ifdef OSL_BIGENDIAN -// little endian <-> big endian switch -static float GetSwapFloat(SvStream& rStream) -{ - float fTmp; - sal_Int8* pPtr = (sal_Int8*)&fTmp; - rStream.ReadSChar(pPtr[3]); - rStream.ReadSChar(pPtr[2]); - rStream.ReadSChar(pPtr[1]); - rStream.ReadSChar(pPtr[0]); - return fTmp; -} -#endif - -struct BLENDFUNCTION -{ - unsigned char aBlendOperation; - unsigned char aBlendFlags; - unsigned char aSrcConstantAlpha; - unsigned char aAlphaFormat; - - friend SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun); -}; - -SvStream& operator>>(SvStream& rInStream, BLENDFUNCTION& rBlendFun) -{ - rInStream.ReadUChar(rBlendFun.aBlendOperation); - rInStream.ReadUChar(rBlendFun.aBlendFlags); - rInStream.ReadUChar(rBlendFun.aSrcConstantAlpha); - rInStream.ReadUChar(rBlendFun.aAlphaFormat); - return rInStream; -} - -SvStream& operator>>(SvStream& rInStream, XForm& rXForm) -{ - if (sizeof(float) != 4) - { - OSL_FAIL( "EnhWMFReader::sizeof( float ) != 4" ); - rXForm = XForm(); - } - else - { -#ifdef OSL_BIGENDIAN - rXForm.eM11 = GetSwapFloat(rInStream); - rXForm.eM12 = GetSwapFloat(rInStream); - rXForm.eM21 = GetSwapFloat(rInStream); - rXForm.eM22 = GetSwapFloat(rInStream); - rXForm.eDx = GetSwapFloat(rInStream); - rXForm.eDy = GetSwapFloat(rInStream); -#else - rInStream.ReadFloat(rXForm.eM11); - rInStream.ReadFloat(rXForm.eM12); - rInStream.ReadFloat(rXForm.eM21); - rInStream.ReadFloat(rXForm.eM22); - rInStream.ReadFloat(rXForm.eDx); - rInStream.ReadFloat(rXForm.eDy); -#endif - } - return rInStream; -} - -bool ImplReadRegion( tools::PolyPolygon& rPolyPoly, SvStream& rStream, sal_uInt32 nLen ) -{ - if (nLen == 0) - return false; - - sal_uInt32 nHdSize, nType, nCount, nRgnSize, i; - rStream.ReadUInt32(nHdSize); - rStream.ReadUInt32(nType); - rStream.ReadUInt32(nCount); - rStream.ReadUInt32(nRgnSize); - - if ( nCount > 0 - && nType == RDH_RECTANGLES - && nLen >= ((nCount << 4) + (nHdSize - 16))) - { - sal_Int32 nx1, ny1, nx2, ny2; - - for (i = 0; i < nCount; i++) - { - rStream.ReadInt32(nx1); - rStream.ReadInt32(ny1); - rStream.ReadInt32(nx2); - rStream.ReadInt32(ny2); - - tools::Rectangle aRectangle(Point(nx1, ny1), Point(nx2, ny2)); - - tools::Polygon aPolygon(aRectangle); - tools::PolyPolygon aPolyPolyOr1(aPolygon); - tools::PolyPolygon aPolyPolyOr2(rPolyPoly); - rPolyPoly.GetUnion(aPolyPolyOr1, aPolyPolyOr2); - rPolyPoly = aPolyPolyOr2; - } - return true; - } - return false; -} - -} // anonymous namespace - -EnhWMFReader::EnhWMFReader(SvStream& rStream,GDIMetaFile& rGDIMetaFile,FilterConfigItem* pConfigItem) - : WinMtf(rGDIMetaFile, rStream , pConfigItem) - , bRecordPath(false) - , nRecordCount(0) - , bEMFPlus(false) -{} - -EnhWMFReader::~EnhWMFReader() -{} - -void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC) -{ - if (!bEMFPlus) { - pOut->PassEMFPlusHeaderInfo(); - -#if OSL_DEBUG_LEVEL > 1 - // debug code - write the stream to debug file /tmp/emf-stream.emf - sal_uInt64 const pos = pWMF->Tell(); - pWMF->Seek(0); - SvFileStream file( OUString( "/tmp/emf-stream.emf" ), StreamMode::WRITE | StreamMode::TRUNC ); - - pWMF->WriteStream(file); - file.Flush(); - file.Close(); - - pWMF->Seek( pos ); -#endif - - } - bEMFPlus = true; - - sal_uInt64 const pos = pWMF->Tell(); - void *buffer = malloc( length ); - pOut->PassEMFPlus( buffer, pWMF->ReadBytes(buffer, length) ); - free( buffer ); - pWMF->Seek( pos ); - - bHaveDC = false; - - // skip in SeekRel if impossibly unavailable - sal_uInt32 nRemainder = length; - - const size_t nRequiredHeaderSize = 12; - while (nRemainder >= nRequiredHeaderSize) - { - sal_uInt16 type(0), flags(0); - sal_uInt32 size(0), dataSize(0); - - pWMF->ReadUInt16( type ).ReadUInt16( flags ).ReadUInt32( size ).ReadUInt32( dataSize ); - nRemainder -= nRequiredHeaderSize; - - SAL_INFO ("vcl.emf", "\t\tEMF+ record type: " << std::hex << type << std::dec); - - // Get Device Context - // TODO We should use EmfPlusRecordType::GetDC instead - if( type == 0x4004 ) - { - bHaveDC = true; - SAL_INFO ("vcl.emf", "\t\tEMF+ lock DC (device context)"); - } - - // Get the length of the remaining data of this record based - // on the alleged size - sal_uInt32 nRemainingRecordData = size >= nRequiredHeaderSize ? - size-nRequiredHeaderSize : 0; - // clip to available size - nRemainingRecordData = std::min(nRemainingRecordData, nRemainder); - pWMF->SeekRel(nRemainingRecordData); - nRemainder -= nRemainingRecordData; - } - pWMF->SeekRel(nRemainder); -} - -/** - * Reads polygons from the stream. - * The \<class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16). - * The \<class Drawer> parameter is a c++11 lambda for the method that will draw the polygon. - * skipFirst: if the first point read is the 0th point or the 1st point in the array. - * */ -template <class T, class Drawer> -void EnhWMFReader::ReadAndDrawPolygon(Drawer drawer, const bool skipFirst) -{ - sal_uInt32 nPoints(0), nStartIndex(0); - pWMF->SeekRel( 16 ); - pWMF->ReadUInt32( nPoints ); - if (skipFirst) - { - nPoints ++; - nStartIndex ++; - } - - tools::Polygon aPolygon = ReadPolygon<T>(nStartIndex, nPoints); - drawer(pOut, aPolygon, skipFirst, bRecordPath); -} - -/** - * Reads polygons from the stream. - * The \<class T> parameter is for the type of the points - * nStartIndex: which is the starting index in the polygon of the first point read - * nPoints: number of points - * pWMF: the stream containing the polygons - * */ -template <class T> -tools::Polygon EnhWMFReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints) -{ - bool bRecordOk = nPoints <= SAL_MAX_UINT16; - SAL_WARN_IF(!bRecordOk, "vcl.emf", "polygon record has more polygons than we can handle"); - if (!bRecordOk) - return tools::Polygon(); - - tools::Polygon aPolygon(nPoints); - for (sal_uInt32 i = nStartIndex ; i < nPoints && pWMF->good(); i++ ) - { - T nX, nY; - *pWMF >> nX >> nY; - if (!pWMF->good()) - { - SAL_WARN("vcl.emf", "short read on polygon, truncating"); - aPolygon.SetSize(i); - break; - } - aPolygon[ i ] = Point( nX, nY ); - } - - return aPolygon; -} - -/** - * Reads a polyline from the WMF file and draws it - * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) - * */ -template <class T> -void EnhWMFReader::ReadAndDrawPolyLine() -{ - sal_uInt32 nPoints; - sal_uInt32 i, nNumberOfPolylines( 0 ), nCount( 0 ); - pWMF->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.) - pWMF->ReadUInt32( nNumberOfPolylines ); - pWMF->ReadUInt32( nCount ); // total number of points in all polylines - if (pWMF->Tell() >= nEndPos) - return; - - // taking the amount of points of each polygon, retrieving the total number of points - if ( pWMF->good() && - ( nNumberOfPolylines < SAL_MAX_UINT32 / sizeof( sal_uInt16 ) ) && - ( nNumberOfPolylines * sizeof( sal_uInt16 ) ) <= ( nEndPos - pWMF->Tell() ) - ) - { - std::unique_ptr< sal_uInt32[] > pnPolylinePointCount( new sal_uInt32[ nNumberOfPolylines ] ); - for ( i = 0; i < nNumberOfPolylines && pWMF->good(); i++ ) - { - pWMF->ReadUInt32( nPoints ); - pnPolylinePointCount[ i ] = nPoints; - } - // Get polyline points: - for ( i = 0; ( i < nNumberOfPolylines ) && pWMF->good(); i++ ) - { - tools::Polygon aPolygon = ReadPolygon< T >( 0, pnPolylinePointCount[ i ] ); - pOut->DrawPolyLine( aPolygon, false, bRecordPath ); - } - } -} - -// these are referenced from inside the templates - -SvStream& operator>>(SvStream& rStream, sal_Int16 &n) -{ - return rStream.ReadInt16(n); -} - -SvStream& operator>>(SvStream& rStream, sal_Int32 &n) -{ - return rStream.ReadInt32(n); -} - -/** - * Reads a poly polygon from the WMF file and draws it. - * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) - * */ -template <class T> -void EnhWMFReader::ReadAndDrawPolyPolygon() -{ - sal_uInt32 nPoly(0), nGesPoints(0), nReadPoints(0); - pWMF->SeekRel( 0x10 ); - // Number of polygons - pWMF->ReadUInt32( nPoly ).ReadUInt32( nGesPoints ); - if (pWMF->Tell() >= nEndPos) - return; - if (!pWMF->good()) - return; - //check against numeric overflowing - if (nGesPoints >= SAL_MAX_UINT32 / sizeof(Point)) - return; - if (nPoly >= SAL_MAX_UINT32 / sizeof(sal_uInt16)) - return; - if (nPoly * sizeof(sal_uInt16) > nEndPos - pWMF->Tell()) - return; - - // Get number of points in each polygon - std::vector<sal_uInt16> aPoints(nPoly); - for (sal_uInt32 i = 0; i < nPoly && pWMF->good(); ++i) - { - sal_uInt32 nPoints(0); - pWMF->ReadUInt32( nPoints ); - aPoints[i] = (sal_uInt16)nPoints; - } - if ( pWMF->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - pWMF->Tell() ) ) - { - // Get polygon points - tools::PolyPolygon aPolyPoly(nPoly, nPoly); - for (sal_uInt32 i = 0; i < nPoly && pWMF->good(); ++i) - { - const sal_uInt16 nPointCount(aPoints[i]); - std::vector<Point> aPtAry(nPointCount); - for (sal_uInt16 j = 0; j < nPointCount && pWMF->good(); ++j) - { - T nX(0), nY(0); - *pWMF >> nX >> nY; - aPtAry[j] = Point( nX, nY ); - ++nReadPoints; - } - - aPolyPoly.Insert(tools::Polygon(aPtAry.size(), aPtAry.data())); - } - - pOut->DrawPolyPolygon(aPolyPoly, bRecordPath); - } - - OSL_ENSURE(nReadPoints == nGesPoints, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)"); -} - -bool EnhWMFReader::ReadEnhWMF() -{ - sal_uInt32 nStretchBltMode = 0; - sal_uInt32 nNextPos(0), - nW(0), nH(0), nColor(0), nIndex(0), - nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0); - sal_Int32 nX32(0), nY32(0), nx32(0), ny32(0); - - bool bStatus = ReadHeader(); - bool bHaveDC = false; - - static bool bEnableEMFPlus = ( getenv( "EMF_PLUS_DISABLE" ) == nullptr ); - - while( bStatus && nRecordCount-- && pWMF->good()) - { - sal_uInt32 nRecType(0), nRecSize(0); - pWMF->ReadUInt32(nRecType).ReadUInt32(nRecSize); - - if ( !pWMF->good() || ( nRecSize < 8 ) || ( nRecSize & 3 ) ) // Parameters are always divisible by 4 - { - bStatus = false; - break; - } - - auto nCurPos = pWMF->Tell(); - - if (nEndPos < nCurPos - 8) - { - bStatus = false; - break; - } - - const sal_uInt32 nMaxPossibleRecSize = nEndPos - (nCurPos - 8); - if (nRecSize > nMaxPossibleRecSize) - { - bStatus = false; - break; - } - - nNextPos = nCurPos + (nRecSize - 8); - - if( !aBmpSaveList.empty() - && ( nRecType != EMR_STRETCHBLT ) - && ( nRecType != EMR_STRETCHDIBITS ) - ) { - pOut->ResolveBitmapActions( aBmpSaveList ); - } - - bool bFlag = false; - - SAL_INFO ("vcl.emf", "0x" << std::hex << (nNextPos - nRecSize) << "-0x" << nNextPos << " " << record_type_name(nRecType) << " size: " << nRecSize << std::dec); - - if( bEnableEMFPlus && nRecType == EMR_COMMENT ) { - sal_uInt32 length; - - pWMF->ReadUInt32( length ); - - SAL_INFO("vcl.emf", "\tGDI comment, length: " << length); - - if( pWMF->good() && length >= 4 && length <= pWMF->remainingSize() ) { - sal_uInt32 nCommentId; - - pWMF->ReadUInt32( nCommentId ); - - SAL_INFO ("vcl.emf", "\t\tbegin " << (char)(nCommentId & 0xff) << (char)((nCommentId & 0xff00) >> 8) << (char)((nCommentId & 0xff0000) >> 16) << (char)((nCommentId & 0xff000000) >> 24) << " id: 0x" << std::hex << nCommentId << std::dec); - - if( nCommentId == EMR_COMMENT_EMFPLUS && nRecSize >= 12 ) - { - // [MS-EMF] 2.3.3: DataSize includes both CommentIdentifier and CommentRecordParm fields. - // We have already read 4-byte CommentIdentifier, so reduce length appropriately - ReadEMFPlusComment( length-4, bHaveDC ); - } - else if( nCommentId == EMR_COMMENT_PUBLIC && nRecSize >= 12 ) - { - // TODO: ReadGDIComment() - } - else if( nCommentId == EMR_COMMENT_EMFSPOOL && nRecSize >= 12 ) - { - // TODO Implement reading EMFSPOOL comment - - } - else - { - SAL_INFO ("vcl.emf", "\t\tunknown id: 0x" << std::hex << nCommentId << std::dec); - } - } - } - else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF ) - { - switch( nRecType ) - { - case EMR_POLYBEZIERTO : - ReadAndDrawPolygon<sal_Int32>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyBezier( rPolygon, aTo, aRecordPath ); }, true ); - break; - case EMR_POLYBEZIER : - ReadAndDrawPolygon<sal_Int32>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyBezier( rPolygon, aTo, aRecordPath ); }, false ); - break; - - case EMR_POLYGON : - ReadAndDrawPolygon<sal_Int32>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool /*aTo*/, bool aRecordPath ) - { pWinMtfOutput->DrawPolygon( rPolygon, aRecordPath ); }, false ); - break; - - case EMR_POLYLINETO : - ReadAndDrawPolygon<sal_Int32>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyLine( rPolygon, aTo, aRecordPath ); }, true ); - break; - - case EMR_POLYLINE : - ReadAndDrawPolygon<sal_Int32>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyLine( rPolygon, aTo, aRecordPath ); }, false ); - break; - - case EMR_POLYPOLYLINE : - ReadAndDrawPolyLine<sal_Int32>(); - break; - - case EMR_POLYPOLYGON : - ReadAndDrawPolyPolygon<sal_Int32>(); - break; - - case EMR_SETWINDOWEXTEX : - { - pWMF->ReadUInt32( nW ).ReadUInt32( nH ); - pOut->SetWinExt( Size( nW, nH ), true); - } - break; - - case EMR_SETWINDOWORGEX : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->SetWinOrg( Point( nX32, nY32 ), true); - } - break; - - case EMR_SCALEWINDOWEXTEX : - { - pWMF->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 ); - pOut->ScaleWinExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); - } - break; - - case EMR_SETVIEWPORTORGEX : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->SetDevOrg( Point( nX32, nY32 ) ); - } - break; - - case EMR_SCALEVIEWPORTEXTEX : - { - pWMF->ReadUInt32( nNom1 ).ReadUInt32( nDen1 ).ReadUInt32( nNom2 ).ReadUInt32( nDen2 ); - pOut->ScaleDevExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); - } - break; - - case EMR_SETVIEWPORTEXTEX : - { - pWMF->ReadUInt32( nW ).ReadUInt32( nH ); - pOut->SetDevExt( Size( nW, nH ) ); - } - break; - - case EMR_EOF : - nRecordCount = 0; - break; - - case EMR_SETPIXELV : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->DrawPixel( Point( nX32, nY32 ), ReadColor() ); - } - break; - - case EMR_SETMAPMODE : - { - sal_uInt32 nMapMode; - pWMF->ReadUInt32( nMapMode ); - pOut->SetMapMode( nMapMode ); - } - break; - - case EMR_SETBKMODE : - { - pWMF->ReadUInt32( nDat32 ); - pOut->SetBkMode( static_cast<BkMode>(nDat32) ); - } - break; - - case EMR_SETPOLYFILLMODE : - break; - - case EMR_SETROP2 : - { - pWMF->ReadUInt32( nDat32 ); - pOut->SetRasterOp( (WMFRasterOp)nDat32 ); - } - break; - - case EMR_SETSTRETCHBLTMODE : - { - pWMF->ReadUInt32( nStretchBltMode ); - } - break; - - case EMR_SETTEXTALIGN : - { - pWMF->ReadUInt32( nDat32 ); - pOut->SetTextAlign( nDat32 ); - } - break; - - case EMR_SETTEXTCOLOR : - { - pOut->SetTextColor( ReadColor() ); - } - break; - - case EMR_SETBKCOLOR : - { - pOut->SetBkColor( ReadColor() ); - } - break; - - case EMR_OFFSETCLIPRGN : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->MoveClipRegion( Size( nX32, nY32 ) ); - } - break; - - case EMR_MOVETOEX : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->MoveTo( Point( nX32, nY32 ), bRecordPath ); - } - break; - - case EMR_INTERSECTCLIPRECT : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); - pOut->IntersectClipRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); - } - break; - - case EMR_SAVEDC : - { - pOut->Push(); - } - break; - - case EMR_RESTOREDC : - { - pOut->Pop(); - } - break; - - case EMR_SETWORLDTRANSFORM : - { - XForm aTempXForm; - *pWMF >> aTempXForm; - pOut->SetWorldTransform( aTempXForm ); - } - break; - - case EMR_MODIFYWORLDTRANSFORM : - { - sal_uInt32 nMode; - XForm aTempXForm; - *pWMF >> aTempXForm; - pWMF->ReadUInt32( nMode ); - pOut->ModifyWorldTransform( aTempXForm, nMode ); - } - break; - - case EMR_SELECTOBJECT : - { - pWMF->ReadUInt32( nIndex ); - pOut->SelectObject( nIndex ); - } - break; - - case EMR_CREATEPEN : - { - pWMF->ReadUInt32( nIndex ); - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - - LineInfo aLineInfo; - sal_uInt32 nStyle; - Size aSize; - // #fdo39428 Remove SvStream operator>>(long&) - sal_Int32 nTmpW(0), nTmpH(0); - - pWMF->ReadUInt32( nStyle ).ReadInt32( nTmpW ).ReadInt32( nTmpH ); - aSize.Width() = nTmpW; - aSize.Height() = nTmpH; - - if ( aSize.Width() ) - aLineInfo.SetWidth( aSize.Width() ); - - bool bTransparent = false; - switch( nStyle & PS_STYLE_MASK ) - { - case PS_DASHDOTDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 2 ); - break; - case PS_DASHDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 0 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DASH : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 0 ); - break; - case PS_NULL : - bTransparent = true; - aLineInfo.SetStyle( LineStyle::NONE ); - break; - case PS_INSIDEFRAME : - case PS_SOLID : - default : - aLineInfo.SetStyle( LineStyle::Solid ); - } - switch( nStyle & PS_ENDCAP_STYLE_MASK ) - { - case PS_ENDCAP_ROUND : - if ( aSize.Width() ) - { - aLineInfo.SetLineCap( css::drawing::LineCap_ROUND ); - break; - } - SAL_FALLTHROUGH; - case PS_ENDCAP_SQUARE : - if ( aSize.Width() ) - { - aLineInfo.SetLineCap( css::drawing::LineCap_SQUARE ); - break; - } - SAL_FALLTHROUGH; - case PS_ENDCAP_FLAT : - default : - aLineInfo.SetLineCap( css::drawing::LineCap_BUTT ); - } - switch( nStyle & PS_JOIN_STYLE_MASK ) - { - case PS_JOIN_ROUND : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Round ); - break; - case PS_JOIN_MITER : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Miter ); - break; - case PS_JOIN_BEVEL : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Bevel ); - break; - default : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::NONE ); - } - pOut->CreateObjectIndexed(nIndex, o3tl::make_unique<WinMtfLineStyle>( ReadColor(), aLineInfo, bTransparent )); - } - } - break; - - case EMR_EXTCREATEPEN : - { - sal_Int32 elpHatch; - sal_uInt32 offBmi, cbBmi, offBits, cbBits, nStyle, nWidth, nBrushStyle, elpNumEntries; - Color aColorRef; - - pWMF->ReadUInt32( nIndex ); - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - pWMF->ReadUInt32( offBmi ).ReadUInt32( cbBmi ).ReadUInt32( offBits ).ReadUInt32( cbBits ). ReadUInt32( nStyle ).ReadUInt32( nWidth ).ReadUInt32( nBrushStyle ); - aColorRef = ReadColor(); - pWMF->ReadInt32( elpHatch ).ReadUInt32( elpNumEntries ); - - LineInfo aLineInfo; - if ( nWidth ) - aLineInfo.SetWidth( nWidth ); - - bool bTransparent = false; - - switch( nStyle & PS_STYLE_MASK ) - { - case PS_DASHDOTDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 2 ); - break; - case PS_DASHDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 0 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DASH : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 0 ); - break; - case PS_NULL : - bTransparent = true; - aLineInfo.SetStyle( LineStyle::NONE ); - break; - - case PS_INSIDEFRAME : - case PS_SOLID : - default : - aLineInfo.SetStyle( LineStyle::Solid ); - } - switch( nStyle & PS_ENDCAP_STYLE_MASK ) - { - case PS_ENDCAP_ROUND : - if ( aLineInfo.GetWidth() ) - { - aLineInfo.SetLineCap( css::drawing::LineCap_ROUND ); - break; - } - SAL_FALLTHROUGH; - case PS_ENDCAP_SQUARE : - if ( aLineInfo.GetWidth() ) - { - aLineInfo.SetLineCap( css::drawing::LineCap_SQUARE ); - break; - } - SAL_FALLTHROUGH; - case PS_ENDCAP_FLAT : - default : - aLineInfo.SetLineCap( css::drawing::LineCap_BUTT ); - } - switch( nStyle & PS_JOIN_STYLE_MASK ) - { - case PS_JOIN_ROUND : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Round ); - break; - case PS_JOIN_MITER : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Miter ); - break; - case PS_JOIN_BEVEL : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Bevel ); - break; - default : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::NONE ); - } - pOut->CreateObjectIndexed(nIndex, o3tl::make_unique<WinMtfLineStyle>( aColorRef, aLineInfo, bTransparent )); - } - } - break; - - case EMR_CREATEBRUSHINDIRECT : - { - sal_uInt32 nStyle; - pWMF->ReadUInt32( nIndex ); - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - pWMF->ReadUInt32( nStyle ); - pOut->CreateObjectIndexed(nIndex, o3tl::make_unique<WinMtfFillStyle>( ReadColor(), ( nStyle == BS_HOLLOW ) )); - } - } - break; - - case EMR_DELETEOBJECT : - { - pWMF->ReadUInt32( nIndex ); - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - pOut->DeleteObject( nIndex ); - } - break; - - case EMR_ELLIPSE : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); - pOut->DrawEllipse( ReadRectangle( nX32, nY32, nx32, ny32 ) ); - } - break; - - case EMR_RECTANGLE : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ); - pOut->DrawRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); - } - break; - - case EMR_ROUNDRECT : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nW ).ReadUInt32( nH ); - Size aSize( Size( nW, nH ) ); - pOut->DrawRoundRect( ReadRectangle( nX32, nY32, nx32, ny32 ), aSize ); - } - break; - - case EMR_ARC : - { - sal_uInt32 nStartX, nStartY, nEndX, nEndY; - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( nEndY ); - pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); - } - break; - - case EMR_CHORD : - { - sal_uInt32 nStartX, nStartY, nEndX, nEndY; - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( nEndY ); - pOut->DrawChord( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); - } - break; - - case EMR_PIE : - { - sal_uInt32 nStartX, nStartY, nEndX, nEndY; - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( nEndY ); - const tools::Rectangle aRect( ReadRectangle( nX32, nY32, nx32, ny32 )); - - // #i73608# OutputDevice deviates from WMF - // semantics. start==end means full ellipse here. - if( nStartX == nEndX && nStartY == nEndY ) - pOut->DrawEllipse( aRect ); - else - pOut->DrawPie( aRect, Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); - } - break; - - case EMR_LINETO : - { - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ); - pOut->LineTo( Point( nX32, nY32 ), bRecordPath ); - } - break; - - case EMR_ARCTO : - { - sal_uInt32 nStartX, nStartY, nEndX, nEndY; - pWMF->ReadInt32( nX32 ).ReadInt32( nY32 ).ReadInt32( nx32 ).ReadInt32( ny32 ).ReadUInt32( nStartX ).ReadUInt32( nStartY ).ReadUInt32( nEndX ).ReadUInt32( nEndY ); - pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), true ); - } - break; - - case EMR_BEGINPATH : - { - pOut->ClearPath(); - bRecordPath = true; - } - break; - - case EMR_ABORTPATH : - pOut->ClearPath(); - SAL_FALLTHROUGH; - case EMR_ENDPATH : - bRecordPath = false; - break; - - case EMR_CLOSEFIGURE : - pOut->ClosePath(); - break; - - case EMR_FILLPATH : - pOut->StrokeAndFillPath( false, true ); - break; - - case EMR_STROKEANDFILLPATH : - pOut->StrokeAndFillPath( true, true ); - break; - - case EMR_STROKEPATH : - pOut->StrokeAndFillPath( true, false ); - break; - - case EMR_SELECTCLIPPATH : - { - sal_Int32 nClippingMode; - pWMF->ReadInt32(nClippingMode); - pOut->SetClipPath(pOut->GetPathObj(), nClippingMode, true); - } - break; - - case EMR_EXTSELECTCLIPRGN : - { - sal_Int32 nClippingMode, cbRgnData; - pWMF->ReadInt32(cbRgnData); - pWMF->ReadInt32(nClippingMode); - - // This record's region data should be ignored if mode - // is RGN_COPY - see EMF spec section 2.3.2.2 - if (nClippingMode == RGN_COPY) - { - pOut->SetDefaultClipPath(); - } - else - { - tools::PolyPolygon aPolyPoly; - if (cbRgnData) - ImplReadRegion(aPolyPoly, *pWMF, nRecSize); - pOut->SetClipPath(aPolyPoly, nClippingMode, false); - } - - } - break; - - case EMR_ALPHABLEND: - { - sal_Int32 xDest(0), yDest(0), cxDest(0), cyDest(0); - - BLENDFUNCTION aFunc; - sal_Int32 xSrc(0), ySrc(0), cxSrc(0), cySrc(0); - XForm xformSrc; - sal_uInt32 BkColorSrc(0), iUsageSrc(0), offBmiSrc(0); - sal_uInt32 cbBmiSrc(0), offBitsSrc(0), cbBitsSrc(0); - - sal_uInt32 nStart = pWMF->Tell() - 8; - pWMF->SeekRel( 0x10 ); - - pWMF->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest ); - *pWMF >> aFunc; - pWMF->ReadInt32( xSrc ).ReadInt32( ySrc ); - *pWMF >> xformSrc; - pWMF->ReadUInt32( BkColorSrc ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc ) - .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc ).ReadInt32( cxSrc ).ReadInt32( cySrc ) ; - - tools::Rectangle aRect( Point( xDest, yDest ), Size( cxDest+1, cyDest+1 ) ); - - if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) - bStatus = false; - else - { - const sal_uInt32 nSourceSize = cbBmiSrc + cbBitsSrc + 14; - bool bSafeRead = nSourceSize <= (nEndPos - nStartPos); - sal_uInt32 nDeltaToDIB5HeaderSize(0); - const bool bReadAlpha(0x01 == aFunc.aAlphaFormat); - if (bSafeRead && bReadAlpha) - { - // we need to read alpha channel data if AlphaFormat of BLENDFUNCTION is - // AC_SRC_ALPHA (==0x01). To read it, create a temp DIB-File which is ready - // for DIB-5 format - const sal_uInt32 nHeaderSize = getDIBV5HeaderSize(); - if (cbBmiSrc > nHeaderSize) - bSafeRead = false; - else - nDeltaToDIB5HeaderSize = nHeaderSize - cbBmiSrc; - } - if (bSafeRead) - { - const sal_uInt32 nTargetSize(cbBmiSrc + nDeltaToDIB5HeaderSize + cbBitsSrc + 14); - char* pBuf = new char[ nTargetSize ]; - SvMemoryStream aTmp( pBuf, nTargetSize, StreamMode::READ | StreamMode::WRITE ); - - aTmp.ObjectOwnsMemory( true ); - - // write BM-Header (14 bytes) - aTmp.WriteUChar( 'B' ) - .WriteUChar( 'M' ) - .WriteUInt32( cbBitsSrc ) - .WriteUInt16( 0 ) - .WriteUInt16( 0 ) - .WriteUInt32( cbBmiSrc + nDeltaToDIB5HeaderSize + 14 ); - - // copy DIBInfoHeader from source (cbBmiSrc bytes) - pWMF->Seek( nStart + offBmiSrc ); - pWMF->ReadBytes(pBuf + 14, cbBmiSrc); - - if (bReadAlpha) - { - // need to add values for all stuff that DIBV5Header is bigger - // than DIBInfoHeader, all values are correctly initialized to zero, - // so we can use memset here - memset(pBuf + cbBmiSrc + 14, 0, nDeltaToDIB5HeaderSize); - } - - // copy bitmap data from source (offBitsSrc bytes) - pWMF->Seek( nStart + offBitsSrc ); - pWMF->ReadBytes(pBuf + 14 + nDeltaToDIB5HeaderSize + cbBmiSrc, cbBitsSrc); - aTmp.Seek( 0 ); - - // prepare to read and fill BitmapEx - BitmapEx aBitmapEx; - - if(bReadAlpha) - { - Bitmap aBitmap; - AlphaMask aAlpha; - - if(ReadDIBV5(aBitmap, aAlpha, aTmp)) - { - aBitmapEx = BitmapEx(aBitmap, aAlpha); - } - } - else - { - Bitmap aBitmap; - - if(ReadDIB(aBitmap, aTmp, true)) - { - if(0xff != aFunc.aSrcConstantAlpha) - { - // add const alpha channel - aBitmapEx = BitmapEx( - aBitmap, - AlphaMask(aBitmap.GetSizePixel(), &aFunc.aSrcConstantAlpha)); - } - else - { - // just use Bitmap - aBitmapEx = BitmapEx(aBitmap); - } - } - } - - if(!aBitmapEx.IsEmpty()) - { - // test if it is sensible to crop - if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && - ( xSrc >= 0 ) && ( ySrc >= 0 ) && - ( xSrc + cxSrc < aBitmapEx.GetSizePixel().Width() ) && - ( ySrc + cySrc < aBitmapEx.GetSizePixel().Height() ) ) - { - const tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); - - aBitmapEx.Crop( aCropRect ); - } - -#ifdef DBG_UTIL - static bool bDoSaveForVisualControl(false); - - if(bDoSaveForVisualControl) - { - SvFileStream aNew("c:\\metafile_content.png", StreamMode::WRITE|StreamMode::TRUNC); - vcl::PNGWriter aPNGWriter(aBitmapEx); - aPNGWriter.Write(aNew); - } -#endif - aBmpSaveList.emplace_back(new BSaveStruct(aBitmapEx, aRect, SRCAND|SRCINVERT)); - } - } - } - } - break; - - case EMR_BITBLT : // PASSTHROUGH INTENDED - case EMR_STRETCHBLT : - { - sal_Int32 xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc; - sal_uInt32 dwRop, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc; - XForm xformSrc; - - sal_uInt32 nStart = pWMF->Tell() - 8; - - pWMF->SeekRel( 0x10 ); - pWMF->ReadInt32( xDest ).ReadInt32( yDest ).ReadInt32( cxDest ).ReadInt32( cyDest ).ReadUInt32( dwRop ).ReadInt32( xSrc ).ReadInt32( ySrc ) - >> xformSrc; - pWMF->ReadUInt32( nColor ).ReadUInt32( iUsageSrc ).ReadUInt32( offBmiSrc ).ReadUInt32( cbBmiSrc ) - .ReadUInt32( offBitsSrc ).ReadUInt32( cbBitsSrc ); - - if ( nRecType == EMR_STRETCHBLT ) - pWMF->ReadInt32( cxSrc ).ReadInt32( cySrc ); - else - cxSrc = cySrc = 0; - - Bitmap aBitmap; - tools::Rectangle aRect( Point( xDest, yDest ), Size( cxDest, cyDest ) ); - - if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) - bStatus = false; - else - { - sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; - if ( nSize <= ( nEndPos - nStartPos ) ) - { - char* pBuf = new char[ nSize ]; - SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); - aTmp.ObjectOwnsMemory( true ); - aTmp.WriteUChar( 'B' ) - .WriteUChar( 'M' ) - .WriteUInt32( cbBitsSrc ) - .WriteUInt16( 0 ) - .WriteUInt16( 0 ) - .WriteUInt32( cbBmiSrc + 14 ); - pWMF->Seek( nStart + offBmiSrc ); - pWMF->ReadBytes(pBuf + 14, cbBmiSrc); - pWMF->Seek( nStart + offBitsSrc ); - pWMF->ReadBytes(pBuf + 14 + cbBmiSrc, cbBitsSrc); - aTmp.Seek( 0 ); - ReadDIB(aBitmap, aTmp, true); - - // test if it is sensible to crop - if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && - ( xSrc >= 0 ) && ( ySrc >= 0 ) && - ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && - ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) - { - tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); - aBitmap.Crop( aCropRect ); - } - aBmpSaveList.emplace_back(new BSaveStruct(aBitmap, aRect, dwRop)); - } - } - } - break; - - case EMR_STRETCHDIBITS : - { - sal_Int32 xDest, yDest, xSrc, ySrc, cxSrc, cySrc, cxDest, cyDest; - sal_uInt32 offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, iUsageSrc, dwRop; - sal_uInt32 nStart = pWMF->Tell() - 8; - - pWMF->SeekRel( 0x10 ); - pWMF->ReadInt32( xDest ) - .ReadInt32( yDest ) - .ReadInt32( xSrc ) - .ReadInt32( ySrc ) - .ReadInt32( cxSrc ) - .ReadInt32( cySrc ) - .ReadUInt32( offBmiSrc ) - .ReadUInt32( cbBmiSrc ) - .ReadUInt32( offBitsSrc ) - .ReadUInt32( cbBitsSrc ) - .ReadUInt32( iUsageSrc ) - .ReadUInt32( dwRop ) - .ReadInt32( cxDest ) - .ReadInt32( cyDest ); - - Bitmap aBitmap; - tools::Rectangle aRect( Point( xDest, yDest ), Size( cxDest, cyDest ) ); - - if ( ((SAL_MAX_UINT32 - 14) < cbBitsSrc) - || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc ) - ) - { - bStatus = false; - } - else - { - sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; - if ( nSize <= ( nEndPos - nStartPos ) ) - { - char* pBuf = new char[ nSize ]; - SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); - aTmp.ObjectOwnsMemory( true ); - aTmp.WriteUChar( 'B' ) - .WriteUChar( 'M' ) - .WriteUInt32( cbBitsSrc ) - .WriteUInt16( 0 ) - .WriteUInt16( 0 ) - .WriteUInt32( cbBmiSrc + 14 ); - pWMF->Seek( nStart + offBmiSrc ); - pWMF->ReadBytes(pBuf + 14, cbBmiSrc); - pWMF->Seek( nStart + offBitsSrc ); - pWMF->ReadBytes(pBuf + 14 + cbBmiSrc, cbBitsSrc); - aTmp.Seek( 0 ); - ReadDIB(aBitmap, aTmp, true); - - // test if it is sensible to crop - if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && - ( xSrc >= 0 ) && ( ySrc >= 0 ) && - ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && - ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) - { - tools::Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); - aBitmap.Crop( aCropRect ); - } - aBmpSaveList.emplace_back(new BSaveStruct(aBitmap, aRect, dwRop)); - } - } - } - break; - - case EMR_EXTCREATEFONTINDIRECTW : - { - pWMF->ReadUInt32( nIndex ); - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - LOGFONTW aLogFont; - sal_Int32 nTmp; - unsigned char nTmp2; - pWMF->ReadInt32( aLogFont.lfHeight ) - .ReadInt32( aLogFont.lfWidth ) - .ReadInt32( aLogFont.lfEscapement ) - .ReadInt32( nTmp ) // lfOrientation - .ReadInt32( aLogFont.lfWeight ) - .ReadUChar( aLogFont.lfItalic ) - .ReadUChar( aLogFont.lfUnderline ) - .ReadUChar( aLogFont.lfStrikeOut ) - .ReadUChar( aLogFont.lfCharSet ) - .ReadUChar( nTmp2 ) // lfOutPrecision - .ReadUChar( nTmp2 ) // lfClipPrecision - .ReadUChar( nTmp2 ) // lfQuality - .ReadUChar( aLogFont.lfPitchAndFamily ); - - sal_Unicode lfFaceName[LF_FACESIZE+1]; - lfFaceName[LF_FACESIZE] = 0; - for (int i = 0; i < LF_FACESIZE; ++i) - { - sal_uInt16 nChar(0); - pWMF->ReadUInt16(nChar); - lfFaceName[i] = nChar; - } - aLogFont.alfFaceName = OUString( lfFaceName ); - - // #i123216# Not used in the test case of #121382# (always identity in XForm), also - // no hints in ms docu if FontSize should be scaled with WT. Using with the example - // from #i123216# creates errors, so removing. - - // // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely - // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time - // // constraints and dangers - // const XForm& rXF = pOut->GetWorldTransform(); - // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy); - // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight)); - // aLogFont.lfWidth = aTransVec.getX(); - // aLogFont.lfHeight = aTransVec.getY(); - - pOut->CreateObjectIndexed(nIndex, o3tl::make_unique<WinMtfFontStyle>( aLogFont )); - } - } - break; - - case EMR_EXTTEXTOUTA : - bFlag = true; - SAL_FALLTHROUGH; - case EMR_EXTTEXTOUTW : - { - sal_Int32 nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale; - sal_uInt32 nOffString, nOptions, offDx; - sal_Int32 nLen; - - nCurPos = pWMF->Tell() - 8; - - pWMF->ReadInt32( nLeft ).ReadInt32( nTop ).ReadInt32( nRight ).ReadInt32( nBottom ).ReadInt32( nGfxMode ).ReadInt32( nXScale ).ReadInt32( nYScale ) - .ReadInt32( ptlReferenceX ).ReadInt32( ptlReferenceY ).ReadInt32( nLen ).ReadUInt32( nOffString ).ReadUInt32( nOptions ); - - pWMF->SeekRel( 0x10 ); - pWMF->ReadUInt32( offDx ); - - ComplexTextLayoutFlags nTextLayoutMode = ComplexTextLayoutFlags::Default; - if ( nOptions & ETO_RTLREADING ) - nTextLayoutMode = ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::TextOriginLeft; - pOut->SetTextLayoutMode( nTextLayoutMode ); - SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "vcl.emf", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" ); - - Point aPos( ptlReferenceX, ptlReferenceY ); - bool bLenSane = nLen > 0 && nLen < static_cast<sal_Int32>( SAL_MAX_UINT32 / sizeof(sal_Int32) ); - bool bOffStringSane = nOffString <= nEndPos - nCurPos; - if (bLenSane && bOffStringSane) - { - pWMF->Seek( nCurPos + nOffString ); - OUString aText; - if ( bFlag ) - { - if ( nLen <= static_cast<sal_Int32>( nEndPos - pWMF->Tell() ) ) - { - std::unique_ptr<sal_Char[]> pBuf(new sal_Char[ nLen ]); - pWMF->ReadBytes(pBuf.get(), nLen); - aText = OUString(pBuf.get(), nLen, pOut->GetCharSet()); - } - } - else - { - if ( ( nLen * sizeof(sal_Unicode) ) <= ( nEndPos - pWMF->Tell() ) ) - { - std::unique_ptr<sal_Unicode[]> pBuf(new sal_Unicode[ nLen ]); - pWMF->ReadBytes(pBuf.get(), nLen << 1); -#ifdef OSL_BIGENDIAN - sal_Char nTmp, *pTmp = (sal_Char*)( pBuf.get() + nLen ); - while ( pTmp-- != (sal_Char*)pBuf.get() ) - { - nTmp = *pTmp--; - pTmp[ 1 ] = *pTmp; - *pTmp = nTmp; - } -#endif - aText = OUString(pBuf.get(), nLen); - } - } - - std::unique_ptr<long[]> pDXAry, pDYAry; - sal_Int32 nDxSize = nLen * ((nOptions & ETO_PDY) ? 8 : 4); - if ( offDx && (( nCurPos + offDx + nDxSize ) <= nNextPos ) && nNextPos <= nEndPos ) - { - pWMF->Seek( nCurPos + offDx ); - pDXAry.reset( new long[aText.getLength()] ); - if (nOptions & ETO_PDY) - { - pDYAry.reset( new long[aText.getLength()] ); - } - - for (sal_Int32 i = 0; i < aText.getLength(); ++i) - { - sal_Int32 nDxCount = 1; - if (aText.getLength() != nLen) - { - sal_Unicode cUniChar = aText[i]; - OString aTmp(&cUniChar, 1, pOut->GetCharSet()); - if (aTmp.getLength() > 1) - { - nDxCount = aTmp.getLength(); - } - } - - sal_Int32 nDx = 0, nDy = 0; - while (nDxCount--) - { - sal_Int32 nDxTmp = 0; - pWMF->ReadInt32(nDxTmp); - nDx += nDxTmp; - if (nOptions & ETO_PDY) - { - sal_Int32 nDyTmp = 0; - pWMF->ReadInt32(nDyTmp); - nDy += nDyTmp; - } - } - - pDXAry[i] = nDx; - if (nOptions & ETO_PDY) - { - pDYAry[i] = nDy; - } - } - } - pOut->DrawText(aPos, aText, pDXAry.get(), pDYAry.get(), bRecordPath, nGfxMode); - } - } - break; - - case EMR_POLYBEZIERTO16 : - ReadAndDrawPolygon<sal_Int16>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyBezier( rPolygon, aTo, aRecordPath ); }, true ); - break; - - case EMR_POLYBEZIER16 : - ReadAndDrawPolygon<sal_Int16>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyBezier( rPolygon, aTo, aRecordPath ); }, false ); - break; - - case EMR_POLYGON16 : - ReadAndDrawPolygon<sal_Int16>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool /*aTo*/, bool aRecordPath ) - { pWinMtfOutput->DrawPolygon( rPolygon, aRecordPath ); }, false ); - break; - - case EMR_POLYLINETO16 : - ReadAndDrawPolygon<sal_Int16>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyLine( rPolygon, aTo, aRecordPath ); }, true ); - break; - - case EMR_POLYLINE16 : - ReadAndDrawPolygon<sal_Int16>( [] ( std::unique_ptr<WinMtfOutput> &pWinMtfOutput, tools::Polygon& rPolygon, bool aTo, bool aRecordPath ) - { pWinMtfOutput->DrawPolyLine( rPolygon, aTo, aRecordPath ); }, false ); - break; - - case EMR_POLYPOLYLINE16 : - ReadAndDrawPolyLine<sal_Int16>(); - break; - - case EMR_POLYPOLYGON16 : - ReadAndDrawPolyPolygon<sal_Int16>(); - break; - - case EMR_FILLRGN : - { - sal_uInt32 nLen; - tools::PolyPolygon aPolyPoly; - pWMF->SeekRel( 0x10 ); - pWMF->ReadUInt32( nLen ).ReadUInt32( nIndex ); - - if ( ImplReadRegion( aPolyPoly, *pWMF, nRecSize ) ) - { - pOut->Push(); - pOut->SelectObject( nIndex ); - pOut->DrawPolyPolygon( aPolyPoly ); - pOut->Pop(); - } - } - break; - - case EMR_CREATEDIBPATTERNBRUSHPT : - { - sal_uInt32 nStart = pWMF->Tell() - 8; - Bitmap aBitmap; - - pWMF->ReadUInt32( nIndex ); - - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - sal_uInt32 usage, offBmi, cbBmi, offBits, cbBits; - - pWMF->ReadUInt32( usage ); - pWMF->ReadUInt32( offBmi ); - pWMF->ReadUInt32( cbBmi ); - pWMF->ReadUInt32( offBits ); - pWMF->ReadUInt32( cbBits ); - - if ( (cbBits > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBits < cbBmi) ) - bStatus = false; - else if ( offBmi ) - { - sal_uInt32 nSize = cbBmi + cbBits + 14; - if ( nSize <= ( nEndPos - nStartPos ) ) - { - char* pBuf = new char[ nSize ]; - - SvMemoryStream aTmp( pBuf, nSize, StreamMode::READ | StreamMode::WRITE ); - aTmp.ObjectOwnsMemory( true ); - aTmp.WriteUChar( 'B' ) - .WriteUChar( 'M' ) - .WriteUInt32( cbBits ) - .WriteUInt16( 0 ) - .WriteUInt16( 0 ) - .WriteUInt32( cbBmi + 14 ); - pWMF->Seek( nStart + offBmi ); - pWMF->ReadBytes(pBuf + 14, cbBmi); - pWMF->Seek( nStart + offBits ); - pWMF->ReadBytes(pBuf + 14 + cbBmi, cbBits); - aTmp.Seek( 0 ); - ReadDIB(aBitmap, aTmp, true); - } - } - } - - pOut->CreateObjectIndexed(nIndex, o3tl::make_unique<WinMtfFillStyle>( aBitmap )); - } - break; - - case EMR_MASKBLT : SAL_INFO("vcl.emf", "not implemented 'MaskBlt'"); break; - case EMR_PLGBLT : SAL_INFO("vcl.emf", "not implemented 'PlgBlt'"); break; - case EMR_SETDIBITSTODEVICE : SAL_INFO("vcl.emf", "not implemented 'SetDIBitsToDevice'"); break; - case EMR_FRAMERGN : SAL_INFO("vcl.emf", "not implemented 'FrameRgn'"); break; - case EMR_INVERTRGN : SAL_INFO("vcl.emf", "not implemented 'InvertRgn'"); break; - case EMR_PAINTRGN : SAL_INFO("vcl.emf", "not implemented 'PaintRgn'"); break; - case EMR_FLATTENPATH : SAL_INFO("vcl.emf", "not implemented 'FlattenPath'"); break; - case EMR_WIDENPATH : SAL_INFO("vcl.emf", "not implemented 'WidenPath'"); break; - case EMR_POLYDRAW : SAL_INFO("vcl.emf", "not implemented 'Polydraw'"); break; - case EMR_SETARCDIRECTION : SAL_INFO("vcl.emf", "not implemented 'SetArcDirection'"); break; - case EMR_SETPALETTEENTRIES : SAL_INFO("vcl.emf", "not implemented 'SetPaletteEntries'"); break; - case EMR_RESIZEPALETTE : SAL_INFO("vcl.emf", "not implemented 'ResizePalette'"); break; - case EMR_EXTFLOODFILL : SAL_INFO("vcl.emf", "not implemented 'ExtFloodFill'"); break; - case EMR_ANGLEARC : SAL_INFO("vcl.emf", "not implemented 'AngleArc'"); break; - case EMR_SETCOLORADJUSTMENT : SAL_INFO("vcl.emf", "not implemented 'SetColorAdjustment'"); break; - case EMR_POLYDRAW16 : SAL_INFO("vcl.emf", "not implemented 'PolyDraw16'"); break; - case EMR_POLYTEXTOUTA : SAL_INFO("vcl.emf", "not implemented 'PolyTextOutA'"); break; - case EMR_POLYTEXTOUTW : SAL_INFO("vcl.emf", "not implemented 'PolyTextOutW'"); break; - case EMR_CREATECOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'CreateColorSpace'"); break; - case EMR_SETCOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'SetColorSpace'"); break; - case EMR_DELETECOLORSPACE : SAL_INFO("vcl.emf", "not implemented 'DeleteColorSpace'"); break; - case EMR_GLSRECORD : SAL_INFO("vcl.emf", "not implemented 'GlsRecord'"); break; - case EMR_GLSBOUNDEDRECORD : SAL_INFO("vcl.emf", "not implemented 'GlsBoundRecord'"); break; - case EMR_PIXELFORMAT : SAL_INFO("vcl.emf", "not implemented 'PixelFormat'"); break; - case EMR_DRAWESCAPE : SAL_INFO("vcl.emf", "not implemented 'DrawEscape'"); break; - case EMR_EXTESCAPE : SAL_INFO("vcl.emf", "not implemented 'ExtEscape'"); break; - case EMR_STARTDOC : SAL_INFO("vcl.emf", "not implemented 'StartDoc'"); break; - case EMR_SMALLTEXTOUT : SAL_INFO("vcl.emf", "not implemented 'SmallTextOut'"); break; - case EMR_FORCEUFIMAPPING : SAL_INFO("vcl.emf", "not implemented 'ForceUFIMapping'"); break; - case EMR_NAMEDESCAPE : SAL_INFO("vcl.emf", "not implemented 'NamedEscape'"); break; - case EMR_COLORCORRECTPALETTE : SAL_INFO("vcl.emf", "not implemented 'ColorCorrectPalette'"); break; - case EMR_SETICMPROFILEA : SAL_INFO("vcl.emf", "not implemented 'SetICMProfileA'"); break; - case EMR_SETICMPROFILEW : SAL_INFO("vcl.emf", "not implemented 'SetICMProfileW'"); break; - case EMR_TRANSPARENTBLT : SAL_INFO("vcl.emf", "not implemented 'TransparenBlt'"); break; - case EMR_TRANSPARENTDIB : SAL_INFO("vcl.emf", "not implemented 'TransparenDib'"); break; - case EMR_GRADIENTFILL : SAL_INFO("vcl.emf", "not implemented 'GradientFill'"); break; - case EMR_SETLINKEDUFIS : SAL_INFO("vcl.emf", "not implemented 'SetLinkedUFIS'"); break; - - case EMR_SETMAPPERFLAGS : SAL_INFO("vcl.emf", "not implemented 'SetMapperFlags'"); break; - case EMR_SETICMMODE : SAL_INFO("vcl.emf", "not implemented 'SetICMMode'"); break; - case EMR_CREATEMONOBRUSH : SAL_INFO("vcl.emf", "not implemented 'CreateMonoBrush'"); break; - case EMR_SETBRUSHORGEX : SAL_INFO("vcl.emf", "not implemented 'SetBrushOrgEx'"); break; - case EMR_SETMETARGN : SAL_INFO("vcl.emf", "not implemented 'SetMetArgn'"); break; - case EMR_SETMITERLIMIT : SAL_INFO("vcl.emf", "not implemented 'SetMiterLimit'"); break; - case EMR_EXCLUDECLIPRECT : SAL_INFO("vcl.emf", "not implemented 'ExcludeClipRect'"); break; - case EMR_REALIZEPALETTE : SAL_INFO("vcl.emf", "not implemented 'RealizePalette'"); break; - case EMR_SELECTPALETTE : SAL_INFO("vcl.emf", "not implemented 'SelectPalette'"); break; - case EMR_CREATEPALETTE : SAL_INFO("vcl.emf", "not implemented 'CreatePalette'"); break; - case EMR_ALPHADIBBLEND : SAL_INFO("vcl.emf", "not implemented 'AlphaDibBlend'"); break; - case EMR_SETTEXTJUSTIFICATION : SAL_INFO("vcl.emf", "not implemented 'SetTextJustification'"); break; - - case EMR_COMMENT : - case EMR_HEADER : // has already been read at ReadHeader() - break; - - default : SAL_INFO("vcl.emf", "Unknown Meta Action"); break; - } - } - pWMF->Seek( nNextPos ); - } - if( !aBmpSaveList.empty() ) - pOut->ResolveBitmapActions( aBmpSaveList ); - - if ( bStatus ) - pWMF->Seek(nEndPos); - - return bStatus; -}; - -bool EnhWMFReader::ReadHeader() -{ - sal_uInt32 nType, nSignature, nVersion; - sal_uInt32 nHeaderSize, nPalEntries; - - // Spare me the METAFILEHEADER here - // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types) - pWMF->ReadUInt32( nType ).ReadUInt32( nHeaderSize ); - if (nType != 0x00000001) - { - // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001 - SAL_WARN("vcl.emf", "EMF header type is not set to 0x00000001 - possibly corrupted file?"); - return false; - } - - // Start reading the EMR_HEADER Header object - - // bound size (RectL object, see [MS-WMF] section 2.2.2.19) - tools::Rectangle rclBounds = ReadRectangle(); // rectangle in logical units - - // picture frame size (RectL object) - tools::Rectangle rclFrame = ReadRectangle(); // rectangle in device units 1/100th mm - - pWMF->ReadUInt32( nSignature ); - - // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object - // and 2.1.14 FormatSignature Enumeration - if (nSignature != 0x464d4520) - { - SAL_WARN("vcl.emf", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?"); - return false; - } - - pWMF->ReadUInt32(nVersion); // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however - // Microsoft note that not even Windows checks this... - if (nVersion != 0x00010000) - { - SAL_WARN("vcl.emf", "EMF\t\tThis really should be 0x00010000, though not absolutely essential..."); - } - - pWMF->ReadUInt32(nEndPos); // size of metafile - nEndPos += nStartPos; - - sal_uInt32 nStrmPos = pWMF->Tell(); // checking if nEndPos is valid - pWMF->Seek(STREAM_SEEK_TO_END); - sal_uInt32 nActualFileSize = pWMF->Tell(); - - if ( nActualFileSize < nEndPos ) - { - SAL_WARN("vcl.emf", "EMF\t\tEMF Header object records number of bytes as " << nEndPos - << ", however the file size is actually " << nActualFileSize - << " bytes. Possible file corruption?"); - nEndPos = nActualFileSize; - } - pWMF->Seek(nStrmPos); - - pWMF->ReadInt32(nRecordCount); - - if (nRecordCount <= 0) - { - SAL_WARN("vcl.emf", "EMF\t\tEMF Header object shows record counter as <= 0! This shouldn't " - "be possible... indicator of possible file corruption?"); - return false; - } - - // the number of "handles", or graphics objects used in the metafile - - sal_uInt16 nHandlesCount; - pWMF->ReadUInt16(nHandlesCount); - - // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9 - // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific - // value is actually pretty useful in checking if there is possible corruption - - sal_uInt16 nReserved; - pWMF->ReadUInt16(nReserved); - - if ( nReserved != 0x0000 ) - { - SAL_WARN("vcl.emf", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible " - "corruption?"); - } - - // The next 4 bytes specifies the number of characters in the metafile description. - // The 4 bytes after that specific the offset from this record that contains the - // metafile description... zero means no description string. - // For now, we ignore it. - - pWMF->SeekRel(0x8); - - sal_Int32 nPixX, nPixY, nMillX, nMillY; - pWMF->ReadUInt32(nPalEntries); - pWMF->ReadInt32(nPixX); - pWMF->ReadInt32(nPixY); - pWMF->ReadInt32(nMillX); - pWMF->ReadInt32(nMillY); - - pOut->SetrclFrame(rclFrame); - pOut->SetrclBounds(rclBounds); - pOut->SetRefPix(Size( nPixX, nPixY ) ); - pOut->SetRefMill(Size( nMillX, nMillY ) ); - - pWMF->Seek(nStartPos + nHeaderSize); - return true; -} - -tools::Rectangle EnhWMFReader::ReadRectangle() -{ - sal_Int32 nLeft, nTop, nRight, nBottom; - pWMF->ReadInt32(nLeft); - pWMF->ReadInt32(nTop); - pWMF->ReadInt32(nRight); - pWMF->ReadInt32(nBottom); - return tools::Rectangle(nLeft, nTop, nRight, nBottom); -} - -tools::Rectangle EnhWMFReader::ReadRectangle( sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 ) -{ - Point aTL ( Point( x1, y1 ) ); - Point aBR( Point( --x2, --y2 ) ); - return tools::Rectangle( aTL, aBR ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx deleted file mode 100644 index 5053307069db..000000000000 --- a/vcl/source/filter/wmf/winmtf.cxx +++ /dev/null @@ -1,2247 +0,0 @@ -/* -*- 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 <memory> -#include "winmtf.hxx" -#include <basegfx/matrix/b2dhommatrix.hxx> -#include <basegfx/polygon/b2dpolypolygontools.hxx> -#include <vcl/metaact.hxx> -#include <vcl/graphictools.hxx> -#include <vcl/canvastools.hxx> -#include <vcl/metric.hxx> -#include <vcl/svapp.hxx> -#include <tools/fract.hxx> -#include <rtl/strbuf.hxx> -#include <rtl/tencinfo.h> -#include <vcl/virdev.hxx> -#include <o3tl/make_unique.hxx> -#include "officecfg/Setup.hxx" -#include "officecfg/Office/Linguistic.hxx" -#include "unotools/configmgr.hxx" -#include "unotools/wincodepage.hxx" - -#if OSL_DEBUG_LEVEL > 1 -#define EMFP_DEBUG(x) x -#else -#define EMFP_DEBUG(x) -#endif - -void WinMtfClipPath::intersectClipRect( const tools::Rectangle& rRect ) -{ - maClip.intersectRange( - vcl::unotools::b2DRectangleFromRectangle(rRect)); -} - -void WinMtfClipPath::excludeClipRect( const tools::Rectangle& rRect ) -{ - maClip.subtractRange( - vcl::unotools::b2DRectangleFromRectangle(rRect)); -} - -void WinMtfClipPath::setClipPath( const tools::PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ) -{ - const basegfx::B2DPolyPolygon& rB2DPoly=rPolyPolygon.getB2DPolyPolygon(); - switch ( nClippingMode ) - { - case RGN_OR : - maClip.unionPolyPolygon(rB2DPoly); - break; - case RGN_XOR : - maClip.xorPolyPolygon(rB2DPoly); - break; - case RGN_DIFF : - maClip.subtractPolyPolygon(rB2DPoly); - break; - case RGN_AND : - maClip.intersectPolyPolygon(rB2DPoly); - break; - case RGN_COPY : - maClip = basegfx::tools::B2DClipState(rB2DPoly); - break; - } -} - -void WinMtfClipPath::moveClipRegion( const Size& rSize ) -{ - basegfx::B2DHomMatrix aTranslate; - aTranslate.translate(rSize.Width(), rSize.Height()); - maClip.transform(aTranslate); -} - -void WinMtfClipPath::setDefaultClipPath() -{ - // Empty clip region - everything visible - maClip = basegfx::tools::B2DClipState(); -} - -basegfx::B2DPolyPolygon WinMtfClipPath::getClipPath() const -{ - return maClip.getClipPoly(); -} - -void WinMtfPathObj::AddPoint( const Point& rPoint ) -{ - if ( bClosed ) - Insert( tools::Polygon() ); - tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ]; - rPoly.Insert( rPoly.GetSize(), rPoint ); - bClosed = false; -} - -void WinMtfPathObj::AddPolyLine( const tools::Polygon& rPolyLine ) -{ - if ( bClosed ) - Insert( tools::Polygon() ); - tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ]; - rPoly.Insert( rPoly.GetSize(), rPolyLine ); - bClosed = false; -} - -void WinMtfPathObj::AddPolygon( const tools::Polygon& rPoly ) -{ - Insert( rPoly ); - bClosed = true; -} - -void WinMtfPathObj::AddPolyPolygon( const tools::PolyPolygon& rPolyPoly ) -{ - sal_uInt16 i, nCount = rPolyPoly.Count(); - for ( i = 0; i < nCount; i++ ) - Insert( rPolyPoly[ i ] ); - bClosed = true; -} - -void WinMtfPathObj::ClosePath() -{ - if ( Count() ) - { - tools::Polygon& rPoly = static_cast<tools::PolyPolygon&>(*this)[ Count() - 1 ]; - if ( rPoly.GetSize() > 2 ) - { - Point aFirst( rPoly[ 0 ] ); - if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] ) - rPoly.Insert( rPoly.GetSize(), aFirst ); - } - } - bClosed = true; -} - -namespace { - -OUString getLODefaultLanguage() -{ - if (utl::ConfigManager::IsAvoidConfig()) - return OUString("en-US"); - OUString result(officecfg::Office::Linguistic::General::DefaultLocale::get()); - if (result.isEmpty()) - result = officecfg::Setup::L10N::ooSetupSystemLocale::get(); - return result; -} - -} - -WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont ) -{ - rtl_TextEncoding eCharSet; - if ((rFont.alfFaceName == "Symbol") - || (rFont.alfFaceName == "MT Extra")) - eCharSet = RTL_TEXTENCODING_SYMBOL; - else if ((rFont.lfCharSet == DEFAULT_CHARSET) || (rFont.lfCharSet == OEM_CHARSET)) - eCharSet = utl_getWinTextEncodingFromLangStr(getLODefaultLanguage().toUtf8().getStr(), - rFont.lfCharSet == OEM_CHARSET); - else - eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet ); - if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) - eCharSet = RTL_TEXTENCODING_MS_1252; - aFont.SetCharSet( eCharSet ); - aFont.SetFamilyName( rFont.alfFaceName ); - FontFamily eFamily; - switch ( rFont.lfPitchAndFamily & 0xf0 ) - { - case FF_ROMAN: - eFamily = FAMILY_ROMAN; - break; - - case FF_SWISS: - eFamily = FAMILY_SWISS; - break; - - case FF_MODERN: - eFamily = FAMILY_MODERN; - break; - - case FF_SCRIPT: - eFamily = FAMILY_SCRIPT; - break; - - case FF_DECORATIVE: - eFamily = FAMILY_DECORATIVE; - break; - - default: - eFamily = FAMILY_DONTKNOW; - break; - } - aFont.SetFamily( eFamily ); - - FontPitch ePitch; - switch ( rFont.lfPitchAndFamily & 0x0f ) - { - case FIXED_PITCH: - ePitch = PITCH_FIXED; - break; - - case DEFAULT_PITCH: - case VARIABLE_PITCH: - default: - ePitch = PITCH_VARIABLE; - break; - } - aFont.SetPitch( ePitch ); - - FontWeight eWeight; - if (rFont.lfWeight == 0) // default weight SHOULD be used - eWeight = WEIGHT_DONTKNOW; - else if (rFont.lfWeight <= FW_THIN) - eWeight = WEIGHT_THIN; - else if( rFont.lfWeight <= FW_ULTRALIGHT ) - eWeight = WEIGHT_ULTRALIGHT; - else if( rFont.lfWeight <= FW_LIGHT ) - eWeight = WEIGHT_LIGHT; - else if( rFont.lfWeight < FW_MEDIUM ) - eWeight = WEIGHT_NORMAL; - else if( rFont.lfWeight == FW_MEDIUM ) - eWeight = WEIGHT_MEDIUM; - else if( rFont.lfWeight <= FW_SEMIBOLD ) - eWeight = WEIGHT_SEMIBOLD; - else if( rFont.lfWeight <= FW_BOLD ) - eWeight = WEIGHT_BOLD; - else if( rFont.lfWeight <= FW_ULTRABOLD ) - eWeight = WEIGHT_ULTRABOLD; - else - eWeight = WEIGHT_BLACK; - aFont.SetWeight( eWeight ); - - if( rFont.lfItalic ) - aFont.SetItalic( ITALIC_NORMAL ); - - if( rFont.lfUnderline ) - aFont.SetUnderline( LINESTYLE_SINGLE ); - - if( rFont.lfStrikeOut ) - aFont.SetStrikeout( STRIKEOUT_SINGLE ); - - aFont.SetOrientation( (short)rFont.lfEscapement ); - - Size aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) ); - if ( rFont.lfHeight > 0 ) - { - // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading - SolarMutexGuard aGuard; - ScopedVclPtrInstance< VirtualDevice > pVDev; - // converting the cell height into a font height - aFont.SetFontSize( aFontSize ); - pVDev->SetFont( aFont ); - FontMetric aMetric( pVDev->GetFontMetric() ); - long nHeight = aMetric.GetAscent() + aMetric.GetDescent(); - if (nHeight) - { - double fHeight = ((double)aFontSize.Height() * rFont.lfHeight ) / nHeight; - aFontSize.Height() = (sal_Int32)( fHeight + 0.5 ); - } - } - - // Convert height to positive - aFontSize.Height() = std::abs(aFontSize.Height()); - - aFont.SetFontSize(aFontSize); -}; - -WinMtf::WinMtf( GDIMetaFile& rGDIMetaFile, SvStream& rStreamWMF, FilterConfigItem* pConfigItem ) - : pOut( o3tl::make_unique<WinMtfOutput>(rGDIMetaFile) ) - , pWMF( &rStreamWMF ) - , nEndPos( 0 ) - , pFilterConfigItem( pConfigItem ) -{ - SvLockBytes *pLB = pWMF->GetLockBytes(); - if ( pLB ) - pLB->SetSynchronMode(); - - nStartPos = pWMF->Tell(); - - pOut->SetDevOrg( Point() ); - if ( pFilterConfigItem ) - { - xStatusIndicator = pFilterConfigItem->GetStatusIndicator(); - if ( xStatusIndicator.is() ) - { - xStatusIndicator->start( OUString(), 100 ); - } - } -} - -WinMtf::~WinMtf() -{ - if ( xStatusIndicator.is() ) - xStatusIndicator->end(); -} - -void WinMtf::Callback( sal_uInt16 nPercent ) -{ - if ( xStatusIndicator.is() ) - xStatusIndicator->setValue( nPercent ); -} - -Color WinMtf::ReadColor() -{ - sal_uInt32 nColor; - pWMF->ReadUInt32( nColor ); - return Color( (sal_uInt8)nColor, (sal_uInt8)( nColor >> 8 ), (sal_uInt8)( nColor >> 16 ) ); -}; - -Point WinMtfOutput::ImplScale(const Point& rPoint) // Hack to set varying defaults for incompletely defined files. -{ - if (!mbIsMapDevSet) - return Point(rPoint.X() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Left(), - rPoint.Y() * UNDOCUMENTED_WIN_RCL_RELATION - mrclFrame.Top()); - else - return rPoint; -} - -Point WinMtfOutput::ImplMap( const Point& rPt ) -{ - if ( mnWinExtX && mnWinExtY ) - { - double fX = rPt.X(); - double fY = rPt.Y(); - - double fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx; - double fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy; - - if ( mnGfxMode == GM_COMPATIBLE ) - { - switch( mnMapMode ) - { - case MM_LOENGLISH : - { - fX2 -= mnWinOrgX; - fY2 = mnWinOrgY-fY2; - fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10; - fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; - } - break; - case MM_HIENGLISH : - { - fX2 -= mnWinOrgX; - fY2 = mnWinOrgY-fY2; - fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH; - fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; - } - break; - case MM_TWIPS: - { - fX2 -= mnWinOrgX; - fY2 = mnWinOrgY-fY2; - fX2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS; - fY2 *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; - } - break; - case MM_LOMETRIC : - { - fX2 -= mnWinOrgX; - fY2 = mnWinOrgY-fY2; - fX2 *= 10; - fY2 *= 10; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; - } - break; - case MM_HIMETRIC : // in hundredth of a millimeter - { - fX2 -= mnWinOrgX; - fY2 = mnWinOrgY-fY2; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; - } - break; - default : - { - fX2 -= mnWinOrgX; - fY2 -= mnWinOrgY; - fX2 /= mnWinExtX; - fY2 /= mnWinExtY; - fX2 *= mnDevWidth; - fY2 *= mnDevHeight; - fX2 += mnDevOrgX; - fY2 += mnDevOrgY; // fX2, fY2 now in device units - fX2 *= (double)mnMillX * 100.0 / (double)mnPixX; - fY2 *= (double)mnMillY * 100.0 / (double)mnPixY; - } - break; - } - fX2 -= mrclFrame.Left(); - fY2 -= mrclFrame.Top(); - } - return Point( FRound( fX2 ), FRound( fY2 ) ); - } - else - return Point(); -}; - -Size WinMtfOutput::ImplMap(const Size& rSz, bool bDoWorldTransform) -{ - if ( mnWinExtX && mnWinExtY ) - { - // #i121382# apply the whole WorldTransform, else a rotation will be misinterpreted - double fWidth, fHeight; - if (bDoWorldTransform) - { - fWidth = rSz.Width() * maXForm.eM11 + rSz.Height() * maXForm.eM21; - fHeight = rSz.Width() * maXForm.eM12 + rSz.Height() * maXForm.eM22; - } - else - { - //take the scale, but not the rotation - basegfx::B2DHomMatrix aMatrix(maXForm.eM11, maXForm.eM12, 0, - maXForm.eM21, maXForm.eM22, 0); - basegfx::B2DTuple aScale, aTranslate; - double fRotate, fShearX; - if (!aMatrix.decompose(aScale, aTranslate, fRotate, fShearX)) - { - aScale.setX(1.0); - aScale.setY(1.0); - } - fWidth = rSz.Width() * aScale.getX(); - fHeight = rSz.Height() * aScale.getY(); - } - - if ( mnGfxMode == GM_COMPATIBLE ) - { - switch( mnMapMode ) - { - case MM_LOENGLISH : - { - fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10; - fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH*10; - } - break; - case MM_HIENGLISH : - { - fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH; - fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH; - } - break; - case MM_LOMETRIC : - { - fWidth *= 10; - fHeight*=-10; - } - break; - case MM_HIMETRIC : // in hundredth of millimeters - { - fHeight *= -1; - } - break; - case MM_TWIPS: - { - fWidth *= HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS; - fHeight*=-HUNDREDTH_MILLIMETERS_PER_MILLIINCH/MILLIINCH_PER_TWIPS; - } - break; - default : - { - fWidth /= mnWinExtX; - fHeight /= mnWinExtY; - fWidth *= mnDevWidth; - fHeight *= mnDevHeight; - fWidth *= (double)mnMillX * 100 / (double)mnPixX; - fHeight *= (double)mnMillY * 100 / (double)mnPixY; - } - break; - } - } - return Size( FRound( fWidth ), FRound( fHeight ) ); - } - else - return Size(); -} - -tools::Rectangle WinMtfOutput::ImplMap( const tools::Rectangle& rRect ) -{ - return tools::Rectangle( ImplMap( rRect.TopLeft() ), ImplMap( rRect.GetSize() ) ); -} - -void WinMtfOutput::ImplMap( vcl::Font& rFont ) -{ - // !!! HACK: we now always set the width to zero because the OS width is interpreted differently; - // must later be made portable in SV (KA 1996-02-08) - Size aFontSize = ImplMap (rFont.GetFontSize(), false); - - if( aFontSize.Height() < 0 ) - aFontSize.Height() *= -1; - - rFont.SetFontSize( aFontSize ); - - if( ( mnWinExtX * mnWinExtY ) < 0 ) - rFont.SetOrientation( 3600 - rFont.GetOrientation() ); -} - -tools::Polygon& WinMtfOutput::ImplMap( tools::Polygon& rPolygon ) -{ - sal_uInt16 nPoints = rPolygon.GetSize(); - for ( sal_uInt16 i = 0; i < nPoints; i++ ) - { - rPolygon[ i ] = ImplMap( rPolygon[ i ] ); - } - return rPolygon; -} - -void WinMtfOutput::ImplScale( tools::Polygon& rPolygon ) -{ - sal_uInt16 nPoints = rPolygon.GetSize(); - for ( sal_uInt16 i = 0; i < nPoints; i++ ) - { - rPolygon[ i ] = ImplScale( rPolygon[ i ] ); - } -} - -tools::PolyPolygon& WinMtfOutput::ImplScale( tools::PolyPolygon& rPolyPolygon ) -{ - sal_uInt16 nPolys = rPolyPolygon.Count(); - for (sal_uInt16 i = 0; i < nPolys; ++i) - { - ImplScale(rPolyPolygon[i]); - } - return rPolyPolygon; -} - -tools::PolyPolygon& WinMtfOutput::ImplMap( tools::PolyPolygon& rPolyPolygon ) -{ - sal_uInt16 nPolys = rPolyPolygon.Count(); - for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ; - return rPolyPolygon; -} - -void WinMtfOutput::SelectObject( sal_Int32 nIndex ) -{ - if ( nIndex & ENHMETA_STOCK_OBJECT ) - { - sal_uInt16 nStockId = (sal_uInt8)nIndex; - switch( nStockId ) - { - case WHITE_BRUSH : - { - maFillStyle = WinMtfFillStyle( Color( COL_WHITE ) ); - mbFillStyleSelected = true; - } - break; - case LTGRAY_BRUSH : - { - maFillStyle = WinMtfFillStyle( Color( COL_LIGHTGRAY ) ); - mbFillStyleSelected = true; - } - break; - case GRAY_BRUSH : - case DKGRAY_BRUSH : - { - maFillStyle = WinMtfFillStyle( Color( COL_GRAY ) ); - mbFillStyleSelected = true; - } - break; - case BLACK_BRUSH : - { - maFillStyle = WinMtfFillStyle( Color( COL_BLACK ) ); - mbFillStyleSelected = true; - } - break; - case NULL_BRUSH : - { - maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), true ); - mbFillStyleSelected = true; - } - break; - case WHITE_PEN : - { - maLineStyle = WinMtfLineStyle( Color( COL_WHITE ) ); - } - break; - case BLACK_PEN : - { - maLineStyle = WinMtfLineStyle( Color( COL_BLACK ) ); - } - break; - case NULL_PEN : - { - maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), true ); - } - break; - default: - break; - } - } - else - { - nIndex &= 0xffff; // safety check: don't allow index to be > 65535 - - GDIObj *pGDIObj = nullptr; - - if ( (sal_uInt32)nIndex < vGDIObj.size() ) - pGDIObj = vGDIObj[ nIndex ].get(); - - if ( pGDIObj ) - { - const auto pen = dynamic_cast<WinMtfLineStyle*>(pGDIObj); - if (pen) - maLineStyle = *pen; - - const auto brush = dynamic_cast<WinMtfFillStyle*>(pGDIObj); - if (brush) - { - maFillStyle = *brush; - mbFillStyleSelected = true; - } - - const auto font = dynamic_cast<WinMtfFontStyle*>(pGDIObj); - if (font) - maFont = font->aFont; - } - } -} - -void WinMtfOutput::SetTextLayoutMode( ComplexTextLayoutFlags nTextLayoutMode ) -{ - mnTextLayoutMode = nTextLayoutMode; -} - -void WinMtfOutput::SetBkMode( BkMode nMode ) -{ - mnBkMode = nMode; -} - -void WinMtfOutput::SetBkColor( const Color& rColor ) -{ - maBkColor = rColor; -} - -void WinMtfOutput::SetTextColor( const Color& rColor ) -{ - maTextColor = rColor; -} - -void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign ) -{ - mnTextAlign = nAlign; -} - -void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys ) -{ - vGDIObj.resize(nNewEntrys); -} - -void WinMtfOutput::ImplDrawClippedPolyPolygon( const tools::PolyPolygon& rPolyPoly ) -{ - if ( rPolyPoly.Count() ) - { - ImplSetNonPersistentLineColorTransparenz(); - if ( rPolyPoly.Count() == 1 ) - { - if ( rPolyPoly.IsRect() ) - mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) ); - else - { - tools::Polygon aPoly( rPolyPoly[ 0 ] ); - sal_uInt16 nCount = aPoly.GetSize(); - if ( nCount ) - { - if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] ) - { - Point aPoint( aPoly[ 0 ] ); - aPoly.Insert( nCount, aPoint ); - } - mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); - } - } - } - else - mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) ); - } -} - -void WinMtfOutput::CreateObject( std::unique_ptr<GDIObj> pObject ) -{ - if ( pObject ) - { - const auto pLineStyle = dynamic_cast<WinMtfLineStyle*>(pObject.get()); - const auto pFontStyle = dynamic_cast<WinMtfFontStyle*>(pObject.get()); - - if ( pFontStyle ) - { - if (pFontStyle->aFont.GetFontHeight() == 0) - pFontStyle->aFont.SetFontHeight(423); - ImplMap(pFontStyle->aFont); // defaulting to 12pt - } - else if ( pLineStyle ) - { - Size aSize(pLineStyle->aLineInfo.GetWidth(), 0); - aSize = ImplMap(aSize); - pLineStyle->aLineInfo.SetWidth(aSize.Width()); - } - } - std::vector<std::unique_ptr<GDIObj>>::size_type nIndex; - for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ ) - { - if ( !vGDIObj[ nIndex ] ) - break; - } - if ( nIndex == vGDIObj.size() ) - ImplResizeObjectArry( vGDIObj.size() + 16 ); - - vGDIObj[ nIndex ] = std::move(pObject); -} - -void WinMtfOutput::CreateObjectIndexed( sal_Int32 nIndex, std::unique_ptr<GDIObj> pObject ) -{ - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - nIndex &= 0xffff; // safety check: do not allow index to be > 65535 - if ( pObject ) - { - const auto pLineStyle = dynamic_cast<WinMtfLineStyle*>(pObject.get()); - const auto pFontStyle = dynamic_cast<WinMtfFontStyle*>(pObject.get()); - if ( pFontStyle ) - { - if (pFontStyle->aFont.GetFontHeight() == 0) - pFontStyle->aFont.SetFontHeight(423); - ImplMap(pFontStyle->aFont); - } - else if ( pLineStyle ) - { - Size aSize(pLineStyle->aLineInfo.GetWidth(), 0); - pLineStyle->aLineInfo.SetWidth( ImplMap(aSize).Width() ); - - if ( pLineStyle->aLineInfo.GetStyle() == LineStyle::Dash ) - { - aSize.Width() += 1; - long nDotLen = ImplMap( aSize ).Width(); - pLineStyle->aLineInfo.SetDistance( nDotLen ); - pLineStyle->aLineInfo.SetDotLen( nDotLen ); - pLineStyle->aLineInfo.SetDashLen( nDotLen * 3 ); - } - } - } - if ( (sal_uInt32)nIndex >= vGDIObj.size() ) - ImplResizeObjectArry( nIndex + 16 ); - - vGDIObj[ nIndex ] = std::move(pObject); - } -} - -void WinMtfOutput::DeleteObject( sal_Int32 nIndex ) -{ - if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) - { - if ( (sal_uInt32)nIndex < vGDIObj.size() ) - { - vGDIObj[ nIndex ].reset(); - } - } -} - -void WinMtfOutput::IntersectClipRect( const tools::Rectangle& rRect ) -{ - mbClipNeedsUpdate=true; - if ((rRect.Left()-rRect.Right()==0) && (rRect.Top()-rRect.Bottom()==0)) - { - return; // empty rectangles cause trouble - } - aClipPath.intersectClipRect( ImplMap( rRect ) ); -} - -void WinMtfOutput::ExcludeClipRect( const tools::Rectangle& rRect ) -{ - mbClipNeedsUpdate=true; - aClipPath.excludeClipRect( ImplMap( rRect ) ); -} - -void WinMtfOutput::MoveClipRegion( const Size& rSize ) -{ - mbClipNeedsUpdate=true; - aClipPath.moveClipRegion( ImplMap( rSize ) ); -} - -void WinMtfOutput::SetClipPath( const tools::PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, bool bIsMapped ) -{ - mbClipNeedsUpdate = true; - tools::PolyPolygon aPolyPolygon(rPolyPolygon); - - if (!bIsMapped) - { - if (!mbIsMapDevSet && (mnMapMode == MM_ISOTROPIC || mnMapMode == MM_ANISOTROPIC)) - aPolyPolygon = ImplScale(aPolyPolygon); - else - aPolyPolygon = ImplMap(aPolyPolygon); - } - aClipPath.setClipPath(aPolyPolygon, nClippingMode); -} - -void WinMtfOutput::SetDefaultClipPath() -{ - mbClipNeedsUpdate = true; - aClipPath.setDefaultClipPath(); -} - -WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) : - mnLatestTextAlign ( 0 ), - mnTextAlign ( TA_LEFT | TA_TOP | TA_NOUPDATECP ), - maLatestBkColor ( 0x12345678 ), - maBkColor ( COL_WHITE ), - mnLatestTextLayoutMode( ComplexTextLayoutFlags::Default ), - mnTextLayoutMode ( ComplexTextLayoutFlags::Default ), - mnLatestBkMode ( BkMode::NONE ), - mnBkMode ( BkMode::OPAQUE ), - meLatestRasterOp ( RasterOp::Invert ), - meRasterOp ( RasterOp::OverPaint ), - maActPos ( Point() ), - mbNopMode ( false ), - mbFillStyleSelected ( false ), - mbClipNeedsUpdate ( true ), - mbComplexClip ( false ), - mnGfxMode ( GM_COMPATIBLE ), - mnMapMode ( MM_TEXT ), - mnDevOrgX ( 0 ), - mnDevOrgY ( 0 ), - mnDevWidth ( 1 ), - mnDevHeight ( 1 ), - mnWinOrgX ( 0 ), - mnWinOrgY ( 0 ), - mnWinExtX ( 1 ), - mnWinExtY ( 1 ), - mnPixX ( 100 ), - mnPixY ( 100 ), - mnMillX ( 1 ), - mnMillY ( 1 ), - mpGDIMetaFile ( &rGDIMetaFile ) -{ - mbIsMapWinSet = false; - mbIsMapDevSet = false; - mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::CLIPREGION ) ); // The original clipregion has to be on top - // of the stack so it can always be restored - // this is necessary to be able to support - // SetClipRgn( NULL ) and similar ClipRgn actions (SJ) - - maFont.SetFamilyName( "Arial" ); // sj: #i57205#, we do have some scaling problems if using - maFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); // the default font then most times a x11 font is used, we - maFont.SetFontHeight( 423 ); // will prevent this defining a font - - maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 ); - maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 ); - - mnRop = WMFRasterOp::Black; - meRasterOp = RasterOp::OverPaint; - mpGDIMetaFile->AddAction( new MetaRasterOpAction( RasterOp::OverPaint ) ); -} - -WinMtfOutput::~WinMtfOutput() -{ - mpGDIMetaFile->AddAction( new MetaPopAction() ); - mpGDIMetaFile->SetPrefMapMode( MapUnit::Map100thMM ); - if ( mrclFrame.IsEmpty() ) - mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) ); - else - mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() ); -} - -void WinMtfOutput::UpdateClipRegion() -{ - if ( mbClipNeedsUpdate ) - { - mbClipNeedsUpdate = false; - mbComplexClip = false; - - mpGDIMetaFile->AddAction( new MetaPopAction() ); // taking the original clipregion - mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::CLIPREGION ) ); - - // skip for 'no clipping at all' case - if( !aClipPath.isEmpty() ) - { - const basegfx::B2DPolyPolygon& rClipPoly( aClipPath.getClipPath() ); - - mbComplexClip = rClipPoly.count() > 1 - || !basegfx::tools::isRectangle(rClipPoly); - - static bool bEnableComplexClipViaRegion = getenv("SAL_WMF_COMPLEXCLIP_VIA_REGION") != nullptr; - - if (bEnableComplexClipViaRegion) - { - //this makes cases like tdf#45820 work in reasonable time, and I feel in theory should - //be just fine. In practice I see the output is different so needs work before its the - //default, but for file fuzzing it should be good enough - if (mbComplexClip) - { - mpGDIMetaFile->AddAction( - new MetaISectRegionClipRegionAction( - vcl::Region(rClipPoly))); - mbComplexClip = false; - } - else - { - mpGDIMetaFile->AddAction( - new MetaISectRectClipRegionAction( - vcl::unotools::rectangleFromB2DRectangle( - rClipPoly.getB2DRange()))); - } - } - else - { - //normal case - mpGDIMetaFile->AddAction( - new MetaISectRectClipRegionAction( - vcl::unotools::rectangleFromB2DRectangle( - rClipPoly.getB2DRange()))); - } - } - } -} - -void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz() -{ - Color aColor( COL_TRANSPARENT); - WinMtfLineStyle aTransparentLine( aColor, true ); - if ( ! ( maLatestLineStyle == aTransparentLine ) ) - { - maLatestLineStyle = aTransparentLine; - mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) ); - } -} - -void WinMtfOutput::UpdateLineStyle() -{ - if (!( maLatestLineStyle == maLineStyle ) ) - { - maLatestLineStyle = maLineStyle; - mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) ); - } -} - -void WinMtfOutput::UpdateFillStyle() -{ - if ( !mbFillStyleSelected ) // SJ: #i57205# taking care of bkcolor if no brush is selected - maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == BkMode::Transparent ); - if (!( maLatestFillStyle == maFillStyle ) ) - { - maLatestFillStyle = maFillStyle; - if (maFillStyle.aType == WinMtfFillStyleType::Solid) - mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) ); - } -} - -WMFRasterOp WinMtfOutput::SetRasterOp( WMFRasterOp nRasterOp ) -{ - WMFRasterOp nRetROP = mnRop; - if ( nRasterOp != mnRop ) - { - mnRop = nRasterOp; - - if ( mbNopMode && ( nRasterOp != WMFRasterOp::Nop ) ) - { // changing modes from WMFRasterOp::Nop so set pen and brush - maFillStyle = m_NopFillStyle; - maLineStyle = m_NopLineStyle; - mbNopMode = false; - } - switch( nRasterOp ) - { - case WMFRasterOp::Not: - meRasterOp = RasterOp::Invert; - break; - - case WMFRasterOp::XorPen: - meRasterOp = RasterOp::Xor; - break; - - case WMFRasterOp::Nop: - { - meRasterOp = RasterOp::OverPaint; - if( !mbNopMode ) - { - m_NopFillStyle = maFillStyle; - m_NopLineStyle = maLineStyle; - maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), true ); - maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), true ); - mbNopMode = true; - } - } - break; - - default: - meRasterOp = RasterOp::OverPaint; - break; - } - } - if ( nRetROP != nRasterOp ) - mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); - return nRetROP; -}; - -void WinMtfOutput::StrokeAndFillPath( bool bStroke, bool bFill ) -{ - if ( aPathObj.Count() ) - { - UpdateClipRegion(); - UpdateLineStyle(); - UpdateFillStyle(); - if ( bFill ) - { - if ( !bStroke ) - { - mpGDIMetaFile->AddAction( new MetaPushAction( PushFlags::LINECOLOR ) ); - mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), false ) ); - } - if ( aPathObj.Count() == 1 ) - mpGDIMetaFile->AddAction( new MetaPolygonAction( aPathObj.GetObject( 0 ) ) ); - else - mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) ); - - if ( !bStroke ) - mpGDIMetaFile->AddAction( new MetaPopAction() ); - } - else - { - sal_uInt16 i, nCount = aPathObj.Count(); - for ( i = 0; i < nCount; i++ ) - mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) ); - } - ClearPath(); - } -} - -void WinMtfOutput::DrawPixel( const Point& rSource, const Color& rColor ) -{ - mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) ); -} - -void WinMtfOutput::MoveTo( const Point& rPoint, bool bRecordPath ) -{ - Point aDest( ImplMap( rPoint ) ); - if ( bRecordPath ) - { - // fdo#57353 create new subpath for subsequent moves - if ( aPathObj.Count() ) - if ( aPathObj[ aPathObj.Count() - 1 ].GetSize() ) - aPathObj.Insert( tools::Polygon() ); - aPathObj.AddPoint( aDest ); - } - maActPos = aDest; -} - -void WinMtfOutput::LineTo( const Point& rPoint, bool bRecordPath ) -{ - UpdateClipRegion(); - Point aDest( ImplMap( rPoint ) ); - if ( bRecordPath ) - aPathObj.AddPoint( aDest ); - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) ); - } - maActPos = aDest; -} - -void WinMtfOutput::DrawRect( const tools::Rectangle& rRect, bool bEdge ) -{ - UpdateClipRegion(); - UpdateFillStyle(); - - if ( mbComplexClip ) - { - tools::Polygon aPoly( ImplMap( rRect ) ); - tools::PolyPolygon aPolyPolyRect( aPoly ); - tools::PolyPolygon aDest; - tools::PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPolyRect, aDest ); - ImplDrawClippedPolyPolygon( aDest ); - } - else - { - if ( bEdge ) - { - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) ); - } - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); - } - } - else - { - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); - } - } -} - -void WinMtfOutput::DrawRoundRect( const tools::Rectangle& rRect, const Size& rSize ) -{ - UpdateClipRegion(); - UpdateLineStyle(); - UpdateFillStyle(); - mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) ); -} - -void WinMtfOutput::DrawEllipse( const tools::Rectangle& rRect ) -{ - UpdateClipRegion(); - UpdateFillStyle(); - - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - Point aCenter( ImplMap( rRect.Center() ) ); - Size aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) ); - - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); - } - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); - } -} - -void WinMtfOutput::DrawArc( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd, bool bTo ) -{ - UpdateClipRegion(); - UpdateLineStyle(); - UpdateFillStyle(); - - tools::Rectangle aRect( ImplMap( rRect ) ); - Point aStart( ImplMap( rStart ) ); - Point aEnd( ImplMap( rEnd ) ); - - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - if ( aStart == aEnd ) - { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse - Point aCenter( aRect.Center() ); - Size aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ); - - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); - } - else - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Arc ), maLineStyle.aLineInfo ) ); - } - else - mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) ); - - if ( bTo ) - maActPos = aEnd; -} - -void WinMtfOutput::DrawPie( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd ) -{ - UpdateClipRegion(); - UpdateFillStyle(); - - tools::Rectangle aRect( ImplMap( rRect ) ); - Point aStart( ImplMap( rStart ) ); - Point aEnd( ImplMap( rEnd ) ); - - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Pie ), maLineStyle.aLineInfo ) ); - } - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); - } -} - -void WinMtfOutput::DrawChord( const tools::Rectangle& rRect, const Point& rStart, const Point& rEnd ) -{ - UpdateClipRegion(); - UpdateFillStyle(); - - tools::Rectangle aRect( ImplMap( rRect ) ); - Point aStart( ImplMap( rStart ) ); - Point aEnd( ImplMap( rEnd ) ); - - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( tools::Polygon( aRect, aStart, aEnd, PolyStyle::Chord ), maLineStyle.aLineInfo ) ); - } - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); - } -} - -void WinMtfOutput::DrawPolygon( tools::Polygon& rPolygon, bool bRecordPath ) -{ - UpdateClipRegion(); - ImplMap( rPolygon ); - if ( bRecordPath ) - aPathObj.AddPolygon( rPolygon ); - else - { - UpdateFillStyle(); - - if ( mbComplexClip ) - { - tools::PolyPolygon aPolyPoly( rPolygon ); - tools::PolyPolygon aDest; - tools::PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest ); - ImplDrawClippedPolyPolygon( aDest ); - } - else - { - if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash ) ) - { - sal_uInt16 nCount = rPolygon.GetSize(); - if ( nCount ) - { - if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] ) - { - Point aPoint( rPolygon[ 0 ] ); - rPolygon.Insert( nCount, aPoint ); - } - } - ImplSetNonPersistentLineColorTransparenz(); - mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); - } - else - { - UpdateLineStyle(); - - if (maLatestFillStyle.aType != WinMtfFillStyleType::Pattern) - mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); - else { - SvtGraphicFill aFill = SvtGraphicFill( tools::PolyPolygon( rPolygon ), - Color(), - 0.0, - SvtGraphicFill::fillNonZero, - SvtGraphicFill::fillTexture, - SvtGraphicFill::Transform(), - true, - SvtGraphicFill::hatchSingle, - Color(), - SvtGraphicFill::GradientType::Linear, - Color(), - Color(), - 0, - Graphic (maLatestFillStyle.aBmp) ); - - SvMemoryStream aMemStm; - - WriteSvtGraphicFill( aMemStm, aFill ); - - mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0, - static_cast<const sal_uInt8*>(aMemStm.GetData()), - aMemStm.Seek( STREAM_SEEK_TO_END ) ) ); - mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) ); - } - - } - } - } -} - -void WinMtfOutput::DrawPolyPolygon( tools::PolyPolygon& rPolyPolygon, bool bRecordPath ) -{ - UpdateClipRegion(); - - ImplMap( rPolyPolygon ); - - if ( bRecordPath ) - aPathObj.AddPolyPolygon( rPolyPolygon ); - else - { - UpdateFillStyle(); - - if ( mbComplexClip ) - { - tools::PolyPolygon aDest; - tools::PolyPolygon(aClipPath.getClipPath()).GetIntersection( rPolyPolygon, aDest ); - ImplDrawClippedPolyPolygon( aDest ); - } - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) ); - if (maLineStyle.aLineInfo.GetWidth() > 0 || maLineStyle.aLineInfo.GetStyle() == LineStyle::Dash) - { - for (sal_uInt16 nPoly = 0; nPoly < rPolyPolygon.Count(); ++nPoly) - { - mpGDIMetaFile->AddAction(new MetaPolyLineAction(rPolyPolygon[nPoly], maLineStyle.aLineInfo)); - } - } - } - } -} - -void WinMtfOutput::DrawPolyLine( tools::Polygon& rPolygon, bool bTo, bool bRecordPath ) -{ - UpdateClipRegion(); - - sal_uInt16 nPoints = rPolygon.GetSize(); - if (nPoints >= 1) - { - ImplMap( rPolygon ); - if ( bTo ) - { - rPolygon[ 0 ] = maActPos; - maActPos = rPolygon[ rPolygon.GetSize() - 1 ]; - } - if ( bRecordPath ) - aPathObj.AddPolyLine( rPolygon ); - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); - } - } -} - -void WinMtfOutput::DrawPolyBezier( tools::Polygon& rPolygon, bool bTo, bool bRecordPath ) -{ - sal_uInt16 nPoints = rPolygon.GetSize(); - if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) ) - { - UpdateClipRegion(); - - ImplMap( rPolygon ); - if ( bTo ) - { - rPolygon[ 0 ] = maActPos; - maActPos = rPolygon[ nPoints - 1 ]; - } - sal_uInt16 i; - for ( i = 0; ( i + 2 ) < nPoints; ) - { - rPolygon.SetFlags( i++, PolyFlags::Normal ); - rPolygon.SetFlags( i++, PolyFlags::Control ); - rPolygon.SetFlags( i++, PolyFlags::Control ); - } - if ( bRecordPath ) - aPathObj.AddPolyLine( rPolygon ); - else - { - UpdateLineStyle(); - mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); - } - } -} - -void WinMtfOutput::DrawText( Point& rPosition, OUString& rText, long* pDXArry, long* pDYArry, bool bRecordPath, sal_Int32 nGfxMode ) -{ - UpdateClipRegion(); - rPosition = ImplMap( rPosition ); - sal_Int32 nOldGfxMode = GetGfxMode(); - SetGfxMode( GM_COMPATIBLE ); - - if (pDXArry) - { - sal_Int32 nSumX = 0, nSumY = 0; - for (sal_Int32 i = 0; i < rText.getLength(); i++ ) - { - nSumX += pDXArry[i]; - - // #i121382# Map DXArray using WorldTransform - const Size aSizeX(ImplMap(Size(nSumX, 0))); - const basegfx::B2DVector aVectorX(aSizeX.Width(), aSizeX.Height()); - pDXArry[i] = basegfx::fround(aVectorX.getLength()) * (nSumX >= 0 ? 1 : -1); - - if (pDYArry) - { - nSumY += pDYArry[i]; - - const Size aSizeY(ImplMap(Size(0, nSumY))); - const basegfx::B2DVector aVectorY(aSizeY.Width(), aSizeY.Height()); - // Reverse Y - pDYArry[i] = basegfx::fround(aVectorY.getLength()) * (nSumY >= 0 ? -1 : 1); - } - } - } - if ( mnLatestTextLayoutMode != mnTextLayoutMode ) - { - mnLatestTextLayoutMode = mnTextLayoutMode; - mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) ); - } - SetGfxMode( nGfxMode ); - TextAlign eTextAlign; - if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE ) - eTextAlign = ALIGN_BASELINE; - else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM ) - eTextAlign = ALIGN_BOTTOM; - else - eTextAlign = ALIGN_TOP; - bool bChangeFont = false; - if ( mnLatestTextAlign != mnTextAlign ) - { - bChangeFont = true; - mnLatestTextAlign = mnTextAlign; - mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) ); - } - if ( maLatestTextColor != maTextColor ) - { - bChangeFont = true; - maLatestTextColor = maTextColor; - mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) ); - } - bool bChangeFillColor = false; - if ( maLatestBkColor != maBkColor ) - { - bChangeFillColor = true; - maLatestBkColor = maBkColor; - } - if ( mnLatestBkMode != mnBkMode ) - { - bChangeFillColor = true; - mnLatestBkMode = mnBkMode; - } - if ( bChangeFillColor ) - { - bChangeFont = true; - mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) ); - } - vcl::Font aTmp( maFont ); - aTmp.SetColor( maTextColor ); - aTmp.SetFillColor( maBkColor ); - - if( mnBkMode == BkMode::Transparent ) - aTmp.SetTransparent( true ); - else - aTmp.SetTransparent( false ); - - aTmp.SetAlignment( eTextAlign ); - - if ( nGfxMode == GM_ADVANCED ) - { - // check whether there is a font rotation applied via transformation - Point aP1( ImplMap( Point() ) ); - Point aP2( ImplMap( Point( 0, 100 ) ) ); - aP2.X() -= aP1.X(); - aP2.Y() -= aP1.Y(); - double fX = aP2.X(); - double fY = aP2.Y(); - if ( fX ) - { - double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308; - if ( fY > 0 ) - fOrientation = 360 - fOrientation; - fOrientation += 90; - fOrientation *= 10; - fOrientation += aTmp.GetOrientation(); - aTmp.SetOrientation( sal_Int16( fOrientation ) ); - } - } - - if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) ) - { - // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading - SolarMutexGuard aGuard; - ScopedVclPtrInstance< VirtualDevice > pVDev; - sal_Int32 nTextWidth; - Point aActPosDelta; - pVDev->SetMapMode( MapMode( MapUnit::Map100thMM ) ); - pVDev->SetFont( maFont ); - const sal_uInt32 nLen = pDXArry ? rText.getLength() : 0; - if (nLen) - { - nTextWidth = pVDev->GetTextWidth( OUString(rText[ nLen - 1 ]) ); - if( nLen > 1 ) - nTextWidth += pDXArry[ nLen - 2 ]; - // tdf#39894: We should consider the distance to next character cell origin - aActPosDelta.X() = pDXArry[ nLen - 1 ]; - if ( pDYArry ) - { - aActPosDelta.Y() = pDYArry[ nLen - 1 ]; - } - } - else - { - nTextWidth = pVDev->GetTextWidth( rText ); - aActPosDelta.X() = nTextWidth; - } - - if( mnTextAlign & TA_UPDATECP ) - rPosition = maActPos; - - if ( mnTextAlign & TA_RIGHT_CENTER ) - { - Point aDisplacement( ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1, 0 ); - Point().RotateAround(aDisplacement.X(), aDisplacement.Y(), maFont.GetOrientation()); - rPosition -= aDisplacement; - } - - if( mnTextAlign & TA_UPDATECP ) - { - Point().RotateAround(aActPosDelta.X(), aActPosDelta.Y(), maFont.GetOrientation()); - maActPos = rPosition + aActPosDelta; - } - } - if ( bChangeFont || ( maLatestFont != aTmp ) ) - { - maLatestFont = aTmp; - mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) ); - mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlignment() ) ); - mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) ); - mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) ); - } - if ( bRecordPath ) - { - // TODO - } - else - { - if ( pDXArry && pDYArry ) - { - for (sal_Int32 i = 0; i < rText.getLength(); ++i) - { - Point aCharDisplacement( i ? pDXArry[i-1] : 0, i ? pDYArry[i-1] : 0 ); - Point().RotateAround(aCharDisplacement.X(), aCharDisplacement.Y(), maFont.GetOrientation()); - mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition + aCharDisplacement, OUString( rText[i] ), nullptr, 0, 1 ) ); - } - } - else - { - /* because text without dx array is badly scaled, we - will create such an array if necessary */ - long* pDX = pDXArry; - if (!pDXArry) - { - // #i117968# VirtualDevice is not thread safe, but filter is used in multithreading - SolarMutexGuard aGuard; - ScopedVclPtrInstance< VirtualDevice > pVDev; - pDX = new long[ rText.getLength() ]; - pVDev->SetMapMode( MapUnit::Map100thMM ); - pVDev->SetFont( maLatestFont ); - pVDev->GetTextArray( rText, pDX, 0, rText.getLength()); - } - mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, rText.getLength() ) ); - if ( !pDXArry ) // this means we have created our own array - delete[] pDX; // which must be deleted - } - } - SetGfxMode( nOldGfxMode ); -} - -void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx& rBitmap ) -{ - BitmapEx aBmpEx( rBitmap ); - if ( mbComplexClip ) - { - VclPtrInstance< VirtualDevice > pVDev; - MapMode aMapMode( MapUnit::Map100thMM ); - aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) ); - const Size aOutputSizePixel( pVDev->LogicToPixel( rSize, aMapMode ) ); - const Size aSizePixel( rBitmap.GetSizePixel() ); - if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() ) - { - aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) ); - aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) ); - } - pVDev->SetMapMode( aMapMode ); - pVDev->SetOutputSizePixel( aSizePixel ); - pVDev->SetFillColor( Color( COL_BLACK ) ); - const tools::PolyPolygon aClip( aClipPath.getClipPath() ); - pVDev->DrawPolyPolygon( aClip ); - const Point aEmptyPoint; - - // #i50672# Extract whole VDev content (to match size of rBitmap) - pVDev->EnableMapMode( false ); - const Bitmap aVDevMask(pVDev->GetBitmap(aEmptyPoint, aSizePixel)); - - if(aBmpEx.IsTransparent()) - { - // bitmap already uses a Mask or Alpha, we need to blend that with - // the new masking in pVDev - if(aBmpEx.IsAlpha()) - { - // need to blend in AlphaMask quality (8Bit) - AlphaMask fromVDev(aVDevMask); - AlphaMask fromBmpEx(aBmpEx.GetAlpha()); - AlphaMask::ScopedReadAccess pR(fromVDev); - AlphaMask::ScopedWriteAccess pW(fromBmpEx); - - if(pR && pW) - { - const long nWidth(std::min(pR->Width(), pW->Width())); - const long nHeight(std::min(pR->Height(), pW->Height())); - - for(long nY(0); nY < nHeight; nY++) for(long nX(0); nX < nWidth; nX++) - { - const sal_uInt8 nIndR(pR->GetPixelIndex(nY, nX)); - const sal_uInt8 nIndW(pW->GetPixelIndex(nY, nX)); - - // these values represent transparency (0 == no, 255 == fully transparent), - // so to blend these we have to multiply the inverse (opacity) - // and re-invert the result to transparence - const sal_uInt8 nCombined(0x00ff - (((0x00ff - nIndR) * (0x00ff - nIndW)) >> 8)); - - pW->SetPixelIndex(nY, nX, nCombined); - } - } - - pR.reset(); - pW.reset(); - aBmpEx = BitmapEx(aBmpEx.GetBitmap(), fromBmpEx); - } - else - { - // need to blend in Mask quality (1Bit) - Bitmap aMask(aVDevMask.CreateMask(Color(COL_WHITE))); - - if ( rBitmap.GetTransparentColor() == Color( COL_WHITE ) ) - { - aMask.CombineSimple( rBitmap.GetMask(), BmpCombine::Or ); - } - else - { - aMask.CombineSimple( rBitmap.GetMask(), BmpCombine::And ); - } - - aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask ); - } - } - else - { - // no mask yet, create and add new mask. For better quality, use Alpha, - // this allows the drawn mask being processed with AntiAliasing (AAed) - aBmpEx = BitmapEx(rBitmap.GetBitmap(), aVDevMask); - } - } - - if ( aBmpEx.IsTransparent() ) - mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) ); - else - mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) ); -} - -void WinMtfOutput::ResolveBitmapActions( std::vector<std::unique_ptr<BSaveStruct>>& rSaveList ) -{ - UpdateClipRegion(); - - size_t nObjects = rSaveList.size(); - size_t nObjectsLeft = nObjects; - - while ( nObjectsLeft ) - { - size_t i; - size_t nObjectsOfSameSize = 0; - size_t nObjectStartIndex = nObjects - nObjectsLeft; - - BSaveStruct* pSave = rSaveList[nObjectStartIndex].get(); - tools::Rectangle aRect( pSave->aOutRect ); - - for ( i = nObjectStartIndex; i < nObjects; ) - { - nObjectsOfSameSize++; - if ( ++i < nObjects ) - { - pSave = rSaveList[i].get(); - if ( pSave->aOutRect != aRect ) - break; - } - } - Point aPos( ImplMap( aRect.TopLeft() ) ); - Size aSize( ImplMap( aRect.GetSize() ) ); - - for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ ) - { - pSave = rSaveList[i].get(); - - sal_uInt32 nWinRop = pSave->nWinRop; - sal_uInt8 nRasterOperation = (sal_uInt8)( nWinRop >> 16 ); - - sal_uInt32 nUsed = 0; - if ( ( nRasterOperation & 0xf ) != ( nRasterOperation >> 4 ) ) - nUsed |= 1; // pattern is used - if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) ) - nUsed |= 2; // source is used - if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) ) - nUsed |= 4; // destination is used - - if ( (nUsed & 1) && (( nUsed & 2 ) == 0) && nWinRop != PATINVERT ) - { // patterns aren't well supported yet - WMFRasterOp nOldRop = SetRasterOp( WMFRasterOp::NONE ); // in this case nRasterOperation is either 0 or 0xff - UpdateFillStyle(); - DrawRect( aRect, false ); - SetRasterOp( nOldRop ); - } - else - { - bool bDrawn = false; - - if ( i == nObjectStartIndex ) // optimizing, sometimes it is possible to create just one transparent bitmap - { - if ( nObjectsOfSameSize == 2 ) - { - BSaveStruct* pSave2 = rSaveList[i + 1].get(); - if ( ( pSave->aBmpEx.GetPrefSize() == pSave2->aBmpEx.GetPrefSize() ) && - ( pSave->aBmpEx.GetPrefMapMode() == pSave2->aBmpEx.GetPrefMapMode() ) ) - { - // TODO: Strictly speaking, we should - // check whether mask is monochrome, and - // whether image is black (upper branch) - // or white (lower branch). Otherwise, the - // effect is not the same as a masked - // bitmap. - if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) ) - { - Bitmap aMask( pSave->aBmpEx.GetBitmap() ); aMask.Invert(); - BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - bDrawn = true; - i++; - } - // #i20085# This is just the other way - // around as above. Only difference: mask - // is inverted - else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) ) - { - Bitmap aMask( pSave->aBmpEx.GetBitmap() ); - BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - bDrawn = true; - i++; - } - // tdf#90539 - else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCINVERT ) ) - { - Bitmap aMask( pSave->aBmpEx.GetBitmap() ); - BitmapEx aBmpEx( pSave2->aBmpEx.GetBitmap(), aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - bDrawn = true; - i++; - } - } - } - } - - if ( !bDrawn ) - { - Push(); - WMFRasterOp nOldRop = SetRasterOp( WMFRasterOp::CopyPen ); - Bitmap aBitmap( pSave->aBmpEx.GetBitmap() ); - sal_uInt32 nOperation = ( nRasterOperation & 0xf ); - switch( nOperation ) - { - case 0x1 : - case 0xe : - { - if(pSave->aBmpEx.IsAlpha()) - { - ImplDrawBitmap( aPos, aSize, pSave->aBmpEx ); - } - else - { - SetRasterOp( WMFRasterOp::XorPen ); - ImplDrawBitmap( aPos, aSize, aBitmap ); - SetRasterOp( WMFRasterOp::CopyPen ); - Bitmap aMask( aBitmap ); - aMask.Invert(); - BitmapEx aBmpEx( aBitmap, aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - if ( nOperation == 0x1 ) - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - } - } - break; - case 0x7 : - case 0x8 : - { - Bitmap aMask( aBitmap ); - if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 ) // pattern used - { - aBitmap.Convert( BmpConversion::N24Bit ); - aBitmap.Erase( maFillStyle.aFillColor ); - } - BitmapEx aBmpEx( aBitmap, aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - if ( nOperation == 0x7 ) - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - } - break; - - case 0x4 : - case 0xb : - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - SetRasterOp( WMFRasterOp::CopyPen ); - Bitmap aMask( aBitmap ); - aBitmap.Invert(); - BitmapEx aBmpEx( aBitmap, aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - SetRasterOp( WMFRasterOp::XorPen ); - ImplDrawBitmap( aPos, aSize, aBitmap ); - if ( nOperation == 0xb ) - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - } - break; - - case 0x2 : - case 0xd : - { - Bitmap aMask( aBitmap ); - aMask.Invert(); - BitmapEx aBmpEx( aBitmap, aMask ); - ImplDrawBitmap( aPos, aSize, aBmpEx ); - SetRasterOp( WMFRasterOp::XorPen ); - ImplDrawBitmap( aPos, aSize, aBitmap ); - if ( nOperation == 0xd ) - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - } - break; - case 0x6 : - case 0x9 : - { - SetRasterOp( WMFRasterOp::XorPen ); - ImplDrawBitmap( aPos, aSize, aBitmap ); - if ( nOperation == 0x9 ) - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - } - break; - - case 0x0 : // WHITENESS - case 0xf : // BLACKNESS - { // in this case nRasterOperation is either 0 or 0xff - maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) ); - UpdateFillStyle(); - DrawRect( aRect, false ); - } - break; - - case 0x3 : // only source is used - case 0xc : - { - if ( nRasterOperation == 0x33 ) - aBitmap.Invert(); - ImplDrawBitmap( aPos, aSize, aBitmap ); - } - break; - - case 0x5 : // only destination is used - { - SetRasterOp( WMFRasterOp::Not ); - DrawRect( aRect, false ); - } - break; - - case 0xa : // no operation - break; - } - SetRasterOp( nOldRop ); - Pop(); - } - } - } - nObjectsLeft -= nObjectsOfSameSize; - } - - rSaveList.clear(); -} - -void WinMtfOutput::SetDevOrg( const Point& rPoint ) -{ - mnDevOrgX = rPoint.X(); - mnDevOrgY = rPoint.Y(); -} - -void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ) -{ - mnDevOrgX += nXAdd; - mnDevOrgY += nYAdd; -} - -void WinMtfOutput::SetDevExt( const Size& rSize ,bool regular) -{ - if ( rSize.Width() && rSize.Height() ) - { - switch( mnMapMode ) - { - case MM_ISOTROPIC : - case MM_ANISOTROPIC : - { - mnDevWidth = rSize.Width(); - mnDevHeight = rSize.Height(); - } - } - if (regular) - { - mbIsMapDevSet=true; - } - } -} - -void WinMtfOutput::ScaleDevExt( double fX, double fY ) -{ - mnDevWidth = FRound( mnDevWidth * fX ); - mnDevHeight = FRound( mnDevHeight * fY ); -} - -void WinMtfOutput::SetWinOrg( const Point& rPoint , bool bIsEMF) -{ - mnWinOrgX = rPoint.X(); - mnWinOrgY = rPoint.Y(); - if (bIsEMF) - { - SetDevByWin(); - } - mbIsMapWinSet=true; -} - -void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ) -{ - mnWinOrgX += nXAdd; - mnWinOrgY += nYAdd; -} - -void WinMtfOutput::SetDevByWin() //mnWinExt...-stuff has to be assigned before. -{ - if (!mbIsMapDevSet) - { - if ( mnMapMode == MM_ISOTROPIC ) //TODO: WHAT ABOUT ANISOTROPIC??? - { - Size aSize( (mnWinExtX + mnWinOrgX) >> MS_FIXPOINT_BITCOUNT_28_4, - -((mnWinExtY - mnWinOrgY) >> MS_FIXPOINT_BITCOUNT_28_4)); - - SetDevExt(aSize, false); - } - } -} - -void WinMtfOutput::SetWinExt(const Size& rSize, bool bIsEMF) -{ - if (rSize.Width() && rSize.Height()) - { - switch( mnMapMode ) - { - case MM_ISOTROPIC : - case MM_ANISOTROPIC : - { - mnWinExtX = rSize.Width(); - mnWinExtY = rSize.Height(); - if (bIsEMF) - { - SetDevByWin(); - } - mbIsMapWinSet = true; - } - } - } -} - -void WinMtfOutput::ScaleWinExt( double fX, double fY ) -{ - mnWinExtX = FRound( mnWinExtX * fX ); - mnWinExtY = FRound( mnWinExtY * fY ); -} - -void WinMtfOutput::SetrclBounds( const tools::Rectangle& rRect ) -{ - mrclBounds = rRect; -} - -void WinMtfOutput::SetrclFrame( const tools::Rectangle& rRect ) -{ - mrclFrame = rRect; -} - -void WinMtfOutput::SetRefPix( const Size& rSize ) -{ - mnPixX = rSize.Width(); - mnPixY = rSize.Height(); -} - -void WinMtfOutput::SetRefMill( const Size& rSize ) -{ - mnMillX = rSize.Width(); - mnMillY = rSize.Height(); -} - -void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode ) -{ - mnMapMode = nMapMode; - if ( nMapMode == MM_TEXT && !mbIsMapWinSet ) - { - mnWinExtX = mnDevWidth; - mnWinExtY = mnDevHeight; - } - else if ( mnMapMode == MM_HIMETRIC ) - { - mnWinExtX = mnMillX * 100; - mnWinExtY = mnMillY * 100; - } -} - -void WinMtfOutput::SetWorldTransform( const XForm& rXForm ) -{ - maXForm.eM11 = rXForm.eM11; - maXForm.eM12 = rXForm.eM12; - maXForm.eM21 = rXForm.eM21; - maXForm.eM22 = rXForm.eM22; - maXForm.eDx = rXForm.eDx; - maXForm.eDy = rXForm.eDy; -} - -void WinMtfOutput::ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode ) -{ - switch( nMode ) - { - case MWT_IDENTITY : - { - maXForm.eM11 = maXForm.eM22 = 1.0f; - maXForm.eM12 = maXForm.eM21 = maXForm.eDx = maXForm.eDy = 0.0f; - break; - } - - case MWT_RIGHTMULTIPLY : - case MWT_LEFTMULTIPLY : - { - const XForm* pLeft; - const XForm* pRight; - - if ( nMode == MWT_LEFTMULTIPLY ) - { - pLeft = &rXForm; - pRight = &maXForm; - } - else - { - pLeft = &maXForm; - pRight = &rXForm; - } - - float aF[3][3]; - float bF[3][3]; - float cF[3][3]; - - aF[0][0] = pLeft->eM11; - aF[0][1] = pLeft->eM12; - aF[0][2] = 0; - aF[1][0] = pLeft->eM21; - aF[1][1] = pLeft->eM22; - aF[1][2] = 0; - aF[2][0] = pLeft->eDx; - aF[2][1] = pLeft->eDy; - aF[2][2] = 1; - - bF[0][0] = pRight->eM11; - bF[0][1] = pRight->eM12; - bF[0][2] = 0; - bF[1][0] = pRight->eM21; - bF[1][1] = pRight->eM22; - bF[1][2] = 0; - bF[2][0] = pRight->eDx; - bF[2][1] = pRight->eDy; - bF[2][2] = 1; - - int i, j, k; - for ( i = 0; i < 3; i++ ) - { - for ( j = 0; j < 3; j++ ) - { - cF[i][j] = 0; - for ( k = 0; k < 3; k++ ) - cF[i][j] += aF[i][k] * bF[k][j]; - } - } - maXForm.eM11 = cF[0][0]; - maXForm.eM12 = cF[0][1]; - maXForm.eM21 = cF[1][0]; - maXForm.eM22 = cF[1][1]; - maXForm.eDx = cF[2][0]; - maXForm.eDy = cF[2][1]; - break; - } - case MWT_SET: - { - SetWorldTransform(rXForm); - break; - } - } -} - -void WinMtfOutput::Push() // !! to be able to access the original ClipRegion it -{ // is not allowed to use the MetaPushAction() - UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ) - std::shared_ptr<SaveStruct> pSave( new SaveStruct ); - - pSave->aLineStyle = maLineStyle; - pSave->aFillStyle = maFillStyle; - - pSave->aFont = maFont; - pSave->aTextColor = maTextColor; - pSave->nTextAlign = mnTextAlign; - pSave->nTextLayoutMode = mnTextLayoutMode; - pSave->nMapMode = mnMapMode; - pSave->nGfxMode = mnGfxMode; - pSave->nBkMode = mnBkMode; - pSave->aBkColor = maBkColor; - pSave->bFillStyleSelected = mbFillStyleSelected; - - pSave->aActPos = maActPos; - pSave->aXForm = maXForm; - pSave->eRasterOp = meRasterOp; - - pSave->nWinOrgX = mnWinOrgX; - pSave->nWinOrgY = mnWinOrgY; - pSave->nWinExtX = mnWinExtX; - pSave->nWinExtY = mnWinExtY; - pSave->nDevOrgX = mnDevOrgX; - pSave->nDevOrgY = mnDevOrgY; - pSave->nDevWidth = mnDevWidth; - pSave->nDevHeight = mnDevHeight; - - pSave->aPathObj = aPathObj; - pSave->aClipPath = aClipPath; - - vSaveStack.push_back( pSave ); -} - -void WinMtfOutput::Pop() -{ - // Get the latest data from the stack - if( !vSaveStack.empty() ) - { - // Backup the current data on the stack - std::shared_ptr<SaveStruct> pSave( vSaveStack.back() ); - - maLineStyle = pSave->aLineStyle; - maFillStyle = pSave->aFillStyle; - - maFont = pSave->aFont; - maTextColor = pSave->aTextColor; - mnTextAlign = pSave->nTextAlign; - mnTextLayoutMode = pSave->nTextLayoutMode; - mnBkMode = pSave->nBkMode; - mnGfxMode = pSave->nGfxMode; - mnMapMode = pSave->nMapMode; - maBkColor = pSave->aBkColor; - mbFillStyleSelected = pSave->bFillStyleSelected; - - maActPos = pSave->aActPos; - maXForm = pSave->aXForm; - meRasterOp = pSave->eRasterOp; - - mnWinOrgX = pSave->nWinOrgX; - mnWinOrgY = pSave->nWinOrgY; - mnWinExtX = pSave->nWinExtX; - mnWinExtY = pSave->nWinExtY; - mnDevOrgX = pSave->nDevOrgX; - mnDevOrgY = pSave->nDevOrgY; - mnDevWidth = pSave->nDevWidth; - mnDevHeight = pSave->nDevHeight; - - aPathObj = pSave->aPathObj; - if ( ! ( aClipPath == pSave->aClipPath ) ) - { - aClipPath = pSave->aClipPath; - mbClipNeedsUpdate = true; - } - if ( meLatestRasterOp != meRasterOp ) - mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); - vSaveStack.pop_back(); - } -} - -void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ) -{ - rGDIMetaFile.Play( *mpGDIMetaFile ); -} - -void WinMtfOutput::PassEMFPlusHeaderInfo() -{ - EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n")); - - SvMemoryStream mem; - sal_Int32 nLeft, nRight, nTop, nBottom; - - nLeft = mrclFrame.Left(); - nTop = mrclFrame.Top(); - nRight = mrclFrame.Right(); - nBottom = mrclFrame.Bottom(); - - // emf header info - mem.WriteInt32( nLeft ).WriteInt32( nTop ).WriteInt32( nRight ).WriteInt32( nBottom ); - mem.WriteInt32( mnPixX ).WriteInt32( mnPixY ).WriteInt32( mnMillX ).WriteInt32( mnMillY ); - - float one, zero; - - one = 1; - zero = 0; - - // add transformation matrix to be used in vcl's metaact.cxx for - // rotate and scale operations - mem.WriteFloat( one ).WriteFloat( zero ).WriteFloat( zero ).WriteFloat( one ).WriteFloat( zero ).WriteFloat( zero ); - - // need to flush the stream, otherwise GetEndOfData will return 0 - // on windows where the function parameters are probably resolved in reverse order - mem.Flush(); - - mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, static_cast<const sal_uInt8*>(mem.GetData()), mem.GetEndOfData() ) ); - mpGDIMetaFile->UseCanvas( true ); -} - -void WinMtfOutput::PassEMFPlus( void* pBuffer, sal_uInt32 nLength ) -{ - EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength)); - mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8*>(pBuffer), nLength ) ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx deleted file mode 100644 index ff7d3d5307e9..000000000000 --- a/vcl/source/filter/wmf/winmtf.hxx +++ /dev/null @@ -1,718 +0,0 @@ -/* -*- 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 . - */ - -#ifndef INCLUDED_VCL_SOURCE_FILTER_WMF_WINMTF_HXX -#define INCLUDED_VCL_SOURCE_FILTER_WMF_WINMTF_HXX - -#include <memory> -#include <sal/config.h> - -#include <vcl/graph.hxx> -#include <basegfx/tools/b2dclipstate.hxx> -#include <vcl/font.hxx> -#include <vcl/bitmapaccess.hxx> -#include <vcl/lineinfo.hxx> -#include <vcl/fltcall.hxx> -#include <o3tl/make_unique.hxx> - -#define ERROR 0 -#define NULLREGION 1 -#define COMPLEXREGION 3 - -#define RGN_AND 1 -#define RGN_OR 2 -#define RGN_XOR 3 -#define RGN_DIFF 4 -#define RGN_COPY 5 - -enum class BkMode -{ - NONE = 0, - Transparent = 1, - OPAQUE = 2, -}; - -/* xform stuff */ -#define MWT_IDENTITY 1 -#define MWT_LEFTMULTIPLY 2 -#define MWT_RIGHTMULTIPLY 3 -#define MWT_SET 4 - -#define ENHMETA_STOCK_OBJECT 0x80000000 - -/* Stock Logical Objects */ -#define WHITE_BRUSH 0 -#define LTGRAY_BRUSH 1 -#define GRAY_BRUSH 2 -#define DKGRAY_BRUSH 3 -#define BLACK_BRUSH 4 -#define NULL_BRUSH 5 -#define WHITE_PEN 6 -#define BLACK_PEN 7 -#define NULL_PEN 8 -#define ANSI_FIXED_FONT 11 -#define ANSI_VAR_FONT 12 -#define SYSTEM_FIXED_FONT 16 - -enum class WMFRasterOp { - NONE = 0, - Black = 1, - Not = 6, - XorPen = 7, - Nop = 11, - CopyPen = 13 -}; - -/* Mapping modes */ -#define MM_TEXT 1 -#define MM_LOMETRIC 2 -#define MM_HIMETRIC 3 -#define MM_LOENGLISH 4 -#define MM_HIENGLISH 5 -#define MM_TWIPS 6 -#define MM_ISOTROPIC 7 -#define MM_ANISOTROPIC 8 - -/* Graphics modes */ -#define GM_COMPATIBLE 1 -#define GM_ADVANCED 2 - -/* StretchBlt() modes */ -#define BLACKONWHITE 1 -#define WHITEONBLACK 2 -#define COLORONCOLOR 3 -#define HALFTONE 4 -#define STRETCH_ANDSCANS BLACKONWHITE -#define STRETCH_ORSCANS WHITEONBLACK -#define STRETCH_DELETESCANS COLORONCOLOR - -#define LF_FACESIZE 32 - -struct LOGFONTW -{ - sal_Int32 lfHeight; - sal_Int32 lfWidth; - sal_Int32 lfEscapement; - sal_Int32 lfWeight; - sal_uInt8 lfItalic; - sal_uInt8 lfUnderline; - sal_uInt8 lfStrikeOut; - sal_uInt8 lfCharSet; - sal_uInt8 lfPitchAndFamily; - OUString alfFaceName; -}; -struct WMF_EXTERNALHEADER; - -#define TA_NOUPDATECP 0x0000 -#define TA_UPDATECP 0x0001 -#define TA_LEFT 0x0000 -#define TA_RIGHT 0x0002 -#define TA_CENTER 0x0006 -#define TA_RIGHT_CENTER (TA_RIGHT | TA_CENTER) -#define TA_TOP 0x0000 -#define TA_BOTTOM 0x0008 -#define TA_BASELINE 0x0018 - -#define SRCCOPY 0x00CC0020L -#define SRCPAINT 0x00EE0086L -#define SRCAND 0x008800C6L -#define SRCINVERT 0x00660046L -#define SRCERASE 0x00440328L -#define PATCOPY 0x00F00021L -#define PATINVERT 0x005A0049L -#define BLACKNESS 0x00000042L -#define WHITENESS 0x00FF0062L - -#define PS_SOLID 0 -#define PS_DASH 1 -#define PS_DOT 2 -#define PS_DASHDOT 3 -#define PS_DASHDOTDOT 4 -#define PS_NULL 5 -#define PS_INSIDEFRAME 6 -#define PS_STYLE_MASK 15 - -#define PS_ENDCAP_ROUND 0x000 -#define PS_ENDCAP_SQUARE 0x100 -#define PS_ENDCAP_FLAT 0x200 -#define PS_ENDCAP_STYLE_MASK 0xF00 - -#define PS_JOIN_ROUND 0x0000 -#define PS_JOIN_BEVEL 0x1000 -#define PS_JOIN_MITER 0x2000 -#define PS_JOIN_STYLE_MASK 0xF000 - -#define ANSI_CHARSET 0 -#define DEFAULT_CHARSET 1 -#define SYMBOL_CHARSET 2 -#define SHIFTJIS_CHARSET 128 -#define HANGEUL_CHARSET 129 -#define GB2312_CHARSET 134 -#define CHINESEBIG5_CHARSET 136 -#define OEM_CHARSET 255 -/*WINVER >= 0x0400*/ -#define JOHAB_CHARSET 130 -#define HEBREW_CHARSET 177 -#define ARABIC_CHARSET 178 -#define GREEK_CHARSET 161 -#define TURKISH_CHARSET 162 -#define VIETNAMESE_CHARSET 163 -#define THAI_CHARSET 222 -#define EASTEUROPE_CHARSET 238 -#define RUSSIAN_CHARSET 204 -#define MAC_CHARSET 77 -#define BALTIC_CHARSET 186 - -#define ETO_CLIPPED 0x0004 -/*WINVER >= 0x0400*/ -#define ETO_GLYPH_INDEX 0x0010 -#define ETO_RTLREADING 0x0080 -/*_WIN32_WINNT >= 0x0500*/ -#define ETO_PDY 0x2000 - -#define DEFAULT_PITCH 0x00 -#define FIXED_PITCH 0x01 -#define VARIABLE_PITCH 0x02 - -/* Font Families */ -#define FF_DONTCARE 0x00 -#define FF_ROMAN 0x10 -#define FF_SWISS 0x20 -#define FF_MODERN 0x30 -#define FF_SCRIPT 0x40 -#define FF_DECORATIVE 0x50 - -#define FW_THIN 100 -#define FW_EXTRALIGHT 200 -#define FW_LIGHT 300 -#define FW_NORMAL 400 -#define FW_MEDIUM 500 -#define FW_SEMIBOLD 600 -#define FW_BOLD 700 -#define FW_EXTRABOLD 800 -#define FW_ULTRALIGHT 200 -#define FW_ULTRABOLD 800 -#define FW_BLACK 900 - -#define BS_SOLID 0 -#define BS_NULL 1 -#define BS_HOLLOW 1 -#define BS_HATCHED 2 -#define BS_PATTERN 3 -#define BS_INDEXED 4 -#define BS_DIBPATTERN 5 -#define BS_DIBPATTERNPT 6 -#define BS_PATTERN8X8 7 -#define BS_DIBPATTERN8X8 8 -#define BS_MONOPATTERN 9 - - -#define RDH_RECTANGLES 1 - -#define W_MFCOMMENT 15 - -#define PRIVATE_ESCAPE_UNICODE 2 - -//Scalar constants - -#define UNDOCUMENTED_WIN_RCL_RELATION 32 -#define MS_FIXPOINT_BITCOUNT_28_4 4 -#define HUNDREDTH_MILLIMETERS_PER_MILLIINCH 2.54 -#define MILLIINCH_PER_TWIPS 1.44 - -//============================ WMFReader ================================== - -class WinMtfClipPath -{ - basegfx::tools::B2DClipState maClip; - -public: - WinMtfClipPath(): maClip() {}; - - void setClipPath( const tools::PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ); - void intersectClipRect( const tools::Rectangle& rRect ); - void excludeClipRect( const tools::Rectangle& rRect ); - void moveClipRegion( const Size& rSize ); - void setDefaultClipPath(); - - bool isEmpty() const { return maClip.isCleared(); } - - basegfx::B2DPolyPolygon getClipPath() const; - - bool operator==( const WinMtfClipPath& rPath ) const - { - return maClip == rPath.maClip; - }; -}; - -class WinMtfPathObj : public tools::PolyPolygon -{ - bool bClosed; - -public: - - WinMtfPathObj() : - bClosed(true) - {} - - void Init() - { - Clear(); - bClosed = true; - } - - void ClosePath(); - void AddPoint( const Point& rPoint ); - void AddPolygon( const tools::Polygon& rPoly ); - void AddPolyLine( const tools::Polygon& rPoly ); - void AddPolyPolygon( const tools::PolyPolygon& rPolyPolygon ); -}; - -struct GDIObj -{ - virtual ~GDIObj() = default; // Polymorphic base class -}; - -struct WinMtfFontStyle : GDIObj -{ - vcl::Font aFont; - - explicit WinMtfFontStyle( LOGFONTW& rLogFont ); -}; - - -enum class WinMtfFillStyleType -{ - Solid, Pattern -}; - -struct WinMtfFillStyle : GDIObj -{ - Color aFillColor; - bool bTransparent; - WinMtfFillStyleType aType; - Bitmap aBmp; - - WinMtfFillStyle() - : aFillColor(Color(COL_BLACK)) - , bTransparent(false) - , aType(WinMtfFillStyleType::Solid) - {} - - WinMtfFillStyle(const Color& rColor, bool bTrans = false) - : aFillColor(rColor) - , bTransparent(bTrans) - , aType(WinMtfFillStyleType::Solid) - {} - - explicit WinMtfFillStyle(Bitmap& rBmp) - : bTransparent(false) - , aType(WinMtfFillStyleType::Pattern) - , aBmp(rBmp) - {} - - bool operator==( const WinMtfFillStyle& rStyle ) - { - return aFillColor == rStyle.aFillColor - && bTransparent == rStyle.bTransparent - && aType == rStyle.aType; - } -}; - -struct WinMtfLineStyle : GDIObj -{ - Color aLineColor; - LineInfo aLineInfo; - bool bTransparent; - - WinMtfLineStyle() - : aLineColor (COL_BLACK) - , bTransparent(false) - {} - - WinMtfLineStyle(const Color& rColor, bool bTrans = false) - : aLineColor (rColor) - , bTransparent(bTrans) - {} - - WinMtfLineStyle( const Color& rColor, const LineInfo& rStyle, bool bTrans) - : aLineColor (rColor) - , aLineInfo (rStyle) - , bTransparent(bTrans) - {} - - bool operator==( const WinMtfLineStyle& rStyle ) - { - return aLineColor == rStyle.aLineColor - && bTransparent == rStyle.bTransparent - && aLineInfo == rStyle.aLineInfo; - } -}; - -struct XForm -{ - float eM11; - float eM12; - float eM21; - float eM22; - float eDx; - float eDy; - - XForm() - : eM11(1.0f) - , eM12(0.0f) - , eM21(0.0f) - , eM22(1.0f) - , eDx(0.0f) - , eDy(0.0f) - {} -}; - -struct SaveStruct -{ - BkMode nBkMode; - sal_uInt32 nMapMode, nGfxMode; - ComplexTextLayoutFlags nTextLayoutMode; - sal_Int32 nWinOrgX, nWinOrgY, nWinExtX, nWinExtY; - sal_Int32 nDevOrgX, nDevOrgY, nDevWidth, nDevHeight; - - WinMtfLineStyle aLineStyle; - WinMtfFillStyle aFillStyle; - - vcl::Font aFont; - Color aBkColor; - Color aTextColor; - sal_uInt32 nTextAlign; - RasterOp eRasterOp; - - Point aActPos; - WinMtfPathObj aPathObj; - WinMtfClipPath aClipPath; - XForm aXForm; - - bool bFillStyleSelected; -}; - - -struct BSaveStruct -{ - BitmapEx aBmpEx; - tools::Rectangle aOutRect; - sal_uInt32 nWinRop; - - BSaveStruct(const Bitmap& rBmp, const tools::Rectangle& rOutRect, sal_uInt32 nRop) - : aBmpEx(rBmp) - , aOutRect(rOutRect) - , nWinRop(nRop) - {} - - BSaveStruct(const BitmapEx& rBmpEx, const tools::Rectangle& rOutRect, sal_uInt32 nRop) - : aBmpEx(rBmpEx) - , aOutRect(rOutRect) - , nWinRop(nRop) - {} -}; - - -class WinMtfOutput final -{ - WinMtfPathObj aPathObj; - WinMtfClipPath aClipPath; - - WinMtfLineStyle maLatestLineStyle; - WinMtfLineStyle maLineStyle; - WinMtfLineStyle m_NopLineStyle; - WinMtfFillStyle maLatestFillStyle; - WinMtfFillStyle maFillStyle; - WinMtfFillStyle m_NopFillStyle; - vcl::Font maLatestFont; - vcl::Font maFont; - sal_uInt32 mnLatestTextAlign; - sal_uInt32 mnTextAlign; - Color maLatestTextColor; - Color maTextColor; - Color maLatestBkColor; - Color maBkColor; - ComplexTextLayoutFlags mnLatestTextLayoutMode; - ComplexTextLayoutFlags mnTextLayoutMode; - BkMode mnLatestBkMode; - BkMode mnBkMode; - RasterOp meLatestRasterOp; - RasterOp meRasterOp; - - std::vector< std::unique_ptr<GDIObj> > vGDIObj; - - Point maActPos; - - WMFRasterOp mnRop; - bool mbNopMode; - bool mbFillStyleSelected; - bool mbClipNeedsUpdate; - bool mbComplexClip; - - std::vector< std::shared_ptr<SaveStruct> > vSaveStack; - - sal_uInt32 mnGfxMode; - sal_uInt32 mnMapMode; - - XForm maXForm; - sal_Int32 mnDevOrgX, mnDevOrgY; - sal_Int32 mnDevWidth, mnDevHeight; - sal_Int32 mnWinOrgX, mnWinOrgY; // aktuel window origin - sal_Int32 mnWinExtX, mnWinExtY; // aktuel window extend - bool mbIsMapWinSet; - bool mbIsMapDevSet; - - sal_Int32 mnPixX, mnPixY; // Reference Device in pixel - sal_Int32 mnMillX, mnMillY; // Reference Device in Mill - tools::Rectangle mrclFrame; // rectangle in logical units 1/100th mm - tools::Rectangle mrclBounds; - - GDIMetaFile* mpGDIMetaFile; - - void UpdateLineStyle(); - void UpdateFillStyle(); - - Point ImplMap( const Point& rPt ); - Point ImplScale( const Point& rPt ); - Size ImplMap( const Size& rSize, bool bDoWorldTransform = true); - tools::Rectangle ImplMap( const tools::Rectangle& rRectangle ); - void ImplMap( vcl::Font& rFont ); - tools::Polygon& ImplMap( tools::Polygon& rPolygon ); - tools::PolyPolygon& ImplMap( tools::PolyPolygon& rPolyPolygon ); - void ImplScale( tools::Polygon& rPolygon ); - tools::PolyPolygon& ImplScale( tools::PolyPolygon& rPolyPolygon ); - void ImplResizeObjectArry( sal_uInt32 nNewEntry ); - void ImplSetNonPersistentLineColorTransparenz(); - void ImplDrawClippedPolyPolygon( const tools::PolyPolygon& rPolyPoly ); - void ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx& rBitmap ); - -public: - - void SetDevByWin(); //Hack to set varying defaults for incompletely defined files. - void SetDevOrg( const Point& rPoint ); - void SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ); - void SetDevExt( const Size& rSize ,bool regular = true); - void ScaleDevExt( double fX, double fY ); - - void SetWinOrg( const Point& rPoint , bool bIsEMF = false); - void SetWinOrgOffset( sal_Int32 nX, sal_Int32 nY ); - void SetWinExt( const Size& rSize , bool bIsEMF = false); - void ScaleWinExt( double fX, double fY ); - - void SetrclBounds( const tools::Rectangle& rRect ); - void SetrclFrame( const tools::Rectangle& rRect ); - void SetRefPix( const Size& rSize ); - void SetRefMill( const Size& rSize ); - - void SetMapMode( sal_uInt32 mnMapMode ); - void SetWorldTransform( const XForm& rXForm ); - void ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode ); - - void Push(); - void Pop(); - - WMFRasterOp SetRasterOp( WMFRasterOp nRasterOp ); - void StrokeAndFillPath( bool bStroke, bool bFill ); - - void SetGfxMode( sal_Int32 nGfxMode ){ mnGfxMode = nGfxMode; }; - sal_Int32 GetGfxMode() const { return mnGfxMode; }; - void SetBkMode( BkMode nMode ); - void SetBkColor( const Color& rColor ); - void SetTextColor( const Color& rColor ); - void SetTextAlign( sal_uInt32 nAlign ); - - void CreateObject( std::unique_ptr<GDIObj> pObject); - void CreateObjectIndexed( sal_Int32 nIndex, std::unique_ptr<GDIObj> pObject ); - - void CreateObject() - { - CreateObject(o3tl::make_unique<GDIObj>()); - } - - void DeleteObject( sal_Int32 nIndex ); - void SelectObject( sal_Int32 nIndex ); - rtl_TextEncoding GetCharSet(){ return maFont.GetCharSet(); }; - const vcl::Font& GetFont() const { return maFont;} - void SetTextLayoutMode( ComplexTextLayoutFlags nLayoutMode ); - - void ClearPath(){ aPathObj.Init(); }; - void ClosePath(){ aPathObj.ClosePath(); }; - const tools::PolyPolygon& GetPathObj(){ return aPathObj; }; - - void MoveTo( const Point& rPoint, bool bRecordPath = false ); - void LineTo( const Point& rPoint, bool bRecordPath = false ); - void DrawPixel( const Point& rSource, const Color& rColor ); - void DrawRect( const tools::Rectangle& rRect, bool bEdge = true ); - void DrawRoundRect( const tools::Rectangle& rRect, const Size& rSize ); - void DrawEllipse( const tools::Rectangle& rRect ); - void DrawArc( - const tools::Rectangle& rRect, - const Point& rStartAngle, - const Point& rEndAngle, - bool bDrawTo = false - ); - void DrawPie( - const tools::Rectangle& rRect, - const Point& rStartAngle, - const Point& rEndAngle - ); - void DrawChord( - const tools::Rectangle& rRect, - const Point& rStartAngle, - const Point& rEndAngle - ); - void DrawPolygon( tools::Polygon& rPolygon, bool bRecordPath ); - void DrawPolyPolygon( tools::PolyPolygon& rPolyPolygon, bool bRecordPath = false ); - void DrawPolyLine( tools::Polygon& rPolygon, - bool bDrawTo = false, - bool bRecordPath = false - ); - void DrawPolyBezier( tools::Polygon& rPolygin, - bool bDrawTo, - bool bRecordPath - ); - void DrawText( Point& rPosition, - OUString& rString, - long* pDXArry = nullptr, - long* pDYArry = nullptr, - bool bRecordPath = false, - sal_Int32 nGraphicsMode = GM_COMPATIBLE); - - void ResolveBitmapActions( std::vector<std::unique_ptr<BSaveStruct>>& rSaveList ); - - void IntersectClipRect( const tools::Rectangle& rRect ); - void ExcludeClipRect( const tools::Rectangle& rRect ); - void MoveClipRegion( const Size& rSize ); - void SetClipPath( - const tools::PolyPolygon& rPolyPoly, - sal_Int32 nClippingMode, - bool bIsMapped - ); - void SetDefaultClipPath(); - void UpdateClipRegion(); - void AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ); - - void PassEMFPlus( void* pBuffer, sal_uInt32 nLength ); - void PassEMFPlusHeaderInfo(); - - explicit WinMtfOutput( GDIMetaFile& rGDIMetaFile ); - ~WinMtfOutput(); -}; - -class WinMtf -{ -protected: - - std::unique_ptr<WinMtfOutput> pOut; - SvStream* pWMF; // the WMF/EMF file to be read - - sal_uInt32 nStartPos, nEndPos; - std::vector<std::unique_ptr<BSaveStruct>> aBmpSaveList; - - FilterConfigItem* pFilterConfigItem; - - css::uno::Reference< css::task::XStatusIndicator > xStatusIndicator; - - // assures aSampledBrush is the actual brush of the GDIMetaFile - - Color ReadColor(); - void Callback( sal_uInt16 nPercent ); - - WinMtf( - GDIMetaFile& rGDIMetaFile, - SvStream& rStreamWMF, - FilterConfigItem* pConfigItem - ); - ~WinMtf(); -}; - -class EnhWMFReader : public WinMtf -{ - bool bRecordPath; - sal_Int32 nRecordCount; - bool bEMFPlus; - - bool ReadHeader(); - // reads and converts the rectangle - static tools::Rectangle ReadRectangle( sal_Int32, sal_Int32, sal_Int32, sal_Int32 ); - -public: - EnhWMFReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, FilterConfigItem* pConfigItem = nullptr); - ~EnhWMFReader(); - - bool ReadEnhWMF(); -private: - template <class T> void ReadAndDrawPolyPolygon(); - template <class T> void ReadAndDrawPolyLine(); - template <class T> tools::Polygon ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints); - template <class T, class Drawer> void ReadAndDrawPolygon(Drawer drawer, const bool skipFirst); - - tools::Rectangle ReadRectangle(); - void ReadEMFPlusComment(sal_uInt32 length, bool& bHaveDC); -}; - -class WMFReader : public WinMtf -{ -private: - - sal_uInt16 nUnitsPerInch; - sal_uInt32 nRecSize; - - // embedded EMF data - std::unique_ptr<SvMemoryStream> pEMFStream; - - // total number of comment records containing EMF data - sal_uInt32 nEMFRecCount; - - // number of EMF records read - sal_uInt32 nEMFRec; - - // total size of embedded EMF data - sal_uInt32 nEMFSize; - - sal_uInt32 nSkipActions; - - WMF_EXTERNALHEADER* pExternalHeader; - - // reads header of the WMF-Datei - bool ReadHeader(); - - // reads parameters of the record with the functionnumber nFunction. - void ReadRecordParams( sal_uInt16 nFunction ); - - Point ReadPoint(); // reads and converts a point (first X then Y) - Point ReadYX(); // reads and converts a point (first Y then X) - tools::Rectangle ReadRectangle(); // reads and converts a rectangle - Size ReadYXExt(); - void GetPlaceableBound( tools::Rectangle& rSize, SvStream* pStrm ); - -public: - - WMFReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, - FilterConfigItem* pConfigItem, - WMF_EXTERNALHEADER* pExtHeader = nullptr); - - // read WMF file from stream and fill the GDIMetaFile - void ReadWMF(); -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx deleted file mode 100644 index 501f36eabfe9..000000000000 --- a/vcl/source/filter/wmf/winwmf.cxx +++ /dev/null @@ -1,1833 +0,0 @@ -/* -*- 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 "winmtf.hxx" - -#include <memory> -#include <boost/optional.hpp> -#include <vcl/gdimtf.hxx> -#include <vcl/wmf.hxx> -#include <rtl/crc.h> -#include <rtl/tencinfo.h> -#include <osl/endian.h> -#include <vcl/svapp.hxx> -#include <vcl/dibtools.hxx> -#include <tools/fract.hxx> -#include <o3tl/make_unique.hxx> - -// MS Windows defines - -#define W_META_SETBKCOLOR 0x0201 -#define W_META_SETBKMODE 0x0102 -#define W_META_SETMAPMODE 0x0103 -#define W_META_SETROP2 0x0104 -#define W_META_SETRELABS 0x0105 -#define W_META_SETPOLYFILLMODE 0x0106 -#define W_META_SETSTRETCHBLTMODE 0x0107 -#define W_META_SETTEXTCHAREXTRA 0x0108 -#define W_META_SETTEXTCOLOR 0x0209 -#define W_META_SETTEXTJUSTIFICATION 0x020A -#define W_META_SETWINDOWORG 0x020B -#define W_META_SETWINDOWEXT 0x020C -#define W_META_SETVIEWPORTORG 0x020D -#define W_META_SETVIEWPORTEXT 0x020E -#define W_META_OFFSETWINDOWORG 0x020F -#define W_META_SCALEWINDOWEXT 0x0410 -#define W_META_OFFSETVIEWPORTORG 0x0211 -#define W_META_SCALEVIEWPORTEXT 0x0412 -#define W_META_LINETO 0x0213 -#define W_META_MOVETO 0x0214 -#define W_META_EXCLUDECLIPRECT 0x0415 -#define W_META_INTERSECTCLIPRECT 0x0416 -#define W_META_ARC 0x0817 -#define W_META_ELLIPSE 0x0418 -#define W_META_FLOODFILL 0x0419 -#define W_META_PIE 0x081A -#define W_META_RECTANGLE 0x041B -#define W_META_ROUNDRECT 0x061C -#define W_META_PATBLT 0x061D -#define W_META_SAVEDC 0x001E -#define W_META_SETPIXEL 0x041F -#define W_META_OFFSETCLIPRGN 0x0220 -#define W_META_TEXTOUT 0x0521 -#define W_META_BITBLT 0x0922 -#define W_META_STRETCHBLT 0x0B23 -#define W_META_POLYGON 0x0324 -#define W_META_POLYLINE 0x0325 -#define W_META_ESCAPE 0x0626 -#define W_META_RESTOREDC 0x0127 -#define W_META_FILLREGION 0x0228 -#define W_META_FRAMEREGION 0x0429 -#define W_META_INVERTREGION 0x012A -#define W_META_PAINTREGION 0x012B -#define W_META_SELECTCLIPREGION 0x012C -#define W_META_SELECTOBJECT 0x012D -#define W_META_SETTEXTALIGN 0x012E -#define W_META_DRAWTEXT 0x062F -#define W_META_CHORD 0x0830 -#define W_META_SETMAPPERFLAGS 0x0231 -#define W_META_EXTTEXTOUT 0x0a32 -#define W_META_SETDIBTODEV 0x0d33 -#define W_META_SELECTPALETTE 0x0234 -#define W_META_REALIZEPALETTE 0x0035 -#define W_META_ANIMATEPALETTE 0x0436 -#define W_META_SETPALENTRIES 0x0037 -#define W_META_POLYPOLYGON 0x0538 -#define W_META_RESIZEPALETTE 0x0139 -#define W_META_DIBBITBLT 0x0940 -#define W_META_DIBSTRETCHBLT 0x0b41 -#define W_META_DIBCREATEPATTERNBRUSH 0x0142 -#define W_META_STRETCHDIB 0x0f43 -#define W_META_EXTFLOODFILL 0x0548 -#define W_META_RESETDC 0x014C -#define W_META_STARTDOC 0x014D -#define W_META_STARTPAGE 0x004F -#define W_META_ENDPAGE 0x0050 -#define W_META_ABORTDOC 0x0052 -#define W_META_ENDDOC 0x005E -#define W_META_DELETEOBJECT 0x01f0 -#define W_META_CREATEPALETTE 0x00f7 -#define W_META_CREATEBRUSH 0x00F8 -#define W_META_CREATEPATTERNBRUSH 0x01F9 -#define W_META_CREATEPENINDIRECT 0x02FA -#define W_META_CREATEFONTINDIRECT 0x02FB -#define W_META_CREATEBRUSHINDIRECT 0x02FC -#define W_META_CREATEBITMAPINDIRECT 0x02FD -#define W_META_CREATEBITMAP 0x06FE -#define W_META_CREATEREGION 0x06FF - -static void GetWinExtMax( const Point& rSource, tools::Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) -{ - Point aSource( rSource ); - if ( nMapMode == MM_HIMETRIC ) - aSource.Y() = -rSource.Y(); - if ( aSource.X() < rPlaceableBound.Left() ) - rPlaceableBound.Left() = aSource.X(); - if ( aSource.X() > rPlaceableBound.Right() ) - rPlaceableBound.Right() = aSource.X(); - if ( aSource.Y() < rPlaceableBound.Top() ) - rPlaceableBound.Top() = aSource.Y(); - if ( aSource.Y() > rPlaceableBound.Bottom() ) - rPlaceableBound.Bottom() = aSource.Y(); -} - -static void GetWinExtMax( const tools::Rectangle& rSource, tools::Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) -{ - GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode ); - GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode ); -} - -inline Point WMFReader::ReadPoint() -{ - short nX = 0, nY = 0; - pWMF->ReadInt16( nX ).ReadInt16( nY ); - return Point( nX, nY ); -} - -inline Point WMFReader::ReadYX() -{ - short nX = 0, nY = 0; - pWMF->ReadInt16( nY ).ReadInt16( nX ); - return Point( nX, nY ); -} - -tools::Rectangle WMFReader::ReadRectangle() -{ - Point aBR, aTL; - aBR = ReadYX(); - aTL = ReadYX(); - aBR.X()--; - aBR.Y()--; - return tools::Rectangle( aTL, aBR ); -} - -Size WMFReader::ReadYXExt() -{ - short nW=0, nH=0; - pWMF->ReadInt16( nH ).ReadInt16( nW ); - return Size( nW, nH ); -} - -void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) -{ - switch( nFunc ) - { - case W_META_SETBKCOLOR: - { - pOut->SetBkColor( ReadColor() ); - } - break; - - case W_META_SETBKMODE: - { - sal_uInt16 nDat = 0; - pWMF->ReadUInt16( nDat ); - pOut->SetBkMode( static_cast<BkMode>(nDat) ); - } - break; - - // !!! - case W_META_SETMAPMODE: - { - sal_Int16 nMapMode = 0; - pWMF->ReadInt16( nMapMode ); - pOut->SetMapMode( nMapMode ); - } - break; - - case W_META_SETROP2: - { - sal_uInt16 nROP2 = 0; - pWMF->ReadUInt16( nROP2 ); - pOut->SetRasterOp( (WMFRasterOp)nROP2 ); - } - break; - - case W_META_SETTEXTCOLOR: - { - pOut->SetTextColor( ReadColor() ); - } - break; - - case W_META_SETWINDOWORG: - { - pOut->SetWinOrg( ReadYX() ); - } - break; - - case W_META_SETWINDOWEXT: - { - short nWidth = 0, nHeight = 0; - pWMF->ReadInt16( nHeight ).ReadInt16( nWidth ); - pOut->SetWinExt( Size( nWidth, nHeight ) ); - } - break; - - case W_META_OFFSETWINDOWORG: - { - short nXAdd = 0, nYAdd = 0; - pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd ); - pOut->SetWinOrgOffset( nXAdd, nYAdd ); - } - break; - - case W_META_SCALEWINDOWEXT: - { - short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; - pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum ); - if (!nYDenom || !nXDenom) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); - } - break; - - case W_META_SETVIEWPORTORG: - case W_META_SETVIEWPORTEXT: - break; - - case W_META_OFFSETVIEWPORTORG: - { - short nXAdd = 0, nYAdd = 0; - pWMF->ReadInt16( nYAdd ).ReadInt16( nXAdd ); - pOut->SetDevOrgOffset( nXAdd, nYAdd ); - } - break; - - case W_META_SCALEVIEWPORTEXT: - { - short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; - pWMF->ReadInt16( nYDenom ).ReadInt16( nYNum ).ReadInt16( nXDenom ).ReadInt16( nXNum ); - if (!nYDenom || !nXDenom) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); - } - break; - - case W_META_LINETO: - { - pOut->LineTo( ReadYX() ); - } - break; - - case W_META_MOVETO: - { - pOut->MoveTo( ReadYX() ); - } - break; - - case W_META_INTERSECTCLIPRECT: - { - pOut->IntersectClipRect( ReadRectangle() ); - } - break; - - case W_META_RECTANGLE: - { - pOut->DrawRect( ReadRectangle() ); - } - break; - - case W_META_ROUNDRECT: - { - Size aSize( ReadYXExt() ); - pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) ); - } - break; - - case W_META_ELLIPSE: - { - pOut->DrawEllipse( ReadRectangle() ); - } - break; - - case W_META_ARC: - { - Point aEnd( ReadYX() ); - Point aStart( ReadYX() ); - tools::Rectangle aRect( ReadRectangle() ); - aRect.Justify(); - pOut->DrawArc( aRect, aStart, aEnd ); - } - break; - - case W_META_PIE: - { - Point aEnd( ReadYX() ); - Point aStart( ReadYX() ); - tools::Rectangle aRect( ReadRectangle() ); - aRect.Justify(); - - // #i73608# OutputDevice deviates from WMF - // semantics. start==end means full ellipse here. - if( aStart == aEnd ) - pOut->DrawEllipse( aRect ); - else - pOut->DrawPie( aRect, aStart, aEnd ); - } - break; - - case W_META_CHORD: - { - Point aEnd( ReadYX() ); - Point aStart( ReadYX() ); - tools::Rectangle aRect( ReadRectangle() ); - aRect.Justify(); - pOut->DrawChord( aRect, aStart, aEnd ); - } - break; - - case W_META_POLYGON: - { - bool bRecordOk = true; - - sal_uInt16 nPoints(0); - pWMF->ReadUInt16(nPoints); - - if (nPoints > pWMF->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - } - else - { - tools::Polygon aPoly(nPoints); - for (sal_uInt16 i(0); i < nPoints && pWMF->good(); ++i) - aPoly[ i ] = ReadPoint(); - pOut->DrawPolygon(aPoly, false/*bRecordPath*/); - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polygon record has more points than we can handle"); - - bRecordOk &= pWMF->good(); - - if (!bRecordOk) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - } - break; - - case W_META_POLYPOLYGON: - { - sal_uInt16 nPolyCount(0); - // Number of polygons: - pWMF->ReadUInt16( nPolyCount ); - if (nPolyCount && pWMF->good()) - { - bool bRecordOk = true; - if (nPolyCount > pWMF->remainingSize() / sizeof(sal_uInt16)) - { - break; - } - - // Number of points of each polygon. Determine total number of points - std::unique_ptr<sal_uInt16[]> xPolygonPointCounts(new sal_uInt16[nPolyCount]); - sal_uInt16* pnPoints = xPolygonPointCounts.get(); - tools::PolyPolygon aPolyPoly(nPolyCount, nPolyCount); - sal_uInt16 nPoints = 0; - for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a) - { - pWMF->ReadUInt16( pnPoints[a] ); - - if (pnPoints[a] > SAL_MAX_UINT16 - nPoints) - { - bRecordOk = false; - break; - } - - nPoints += pnPoints[a]; - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polypolygon record has more polygons than we can handle"); - - bRecordOk &= pWMF->good(); - - if (!bRecordOk) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - - // Polygon points are: - for (sal_uInt16 a = 0; a < nPolyCount && pWMF->good(); ++a) - { - const sal_uInt16 nPointCount(pnPoints[a]); - - if (nPointCount > pWMF->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - break; - } - - std::unique_ptr<Point[]> xPolygonPoints(new Point[nPointCount]); - Point* pPtAry = xPolygonPoints.get(); - - for(sal_uInt16 b(0); b < nPointCount && pWMF->good(); ++b) - { - pPtAry[b] = ReadPoint(); - } - - aPolyPoly.Insert( tools::Polygon(nPointCount, pPtAry) ); - } - - bRecordOk &= pWMF->good(); - - if (!bRecordOk) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - - pOut->DrawPolyPolygon( aPolyPoly ); - } - } - break; - - case W_META_POLYLINE: - { - bool bRecordOk = true; - - sal_uInt16 nPoints(0); - pWMF->ReadUInt16(nPoints); - - if (nPoints > pWMF->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - } - else - { - tools::Polygon aPoly(nPoints); - for (sal_uInt16 i(0); i < nPoints && pWMF->good(); ++i) - aPoly[ i ] = ReadPoint(); - pOut->DrawPolyLine( aPoly ); - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polyline record has more points than we can handle"); - - bRecordOk &= pWMF->good(); - - if (!bRecordOk) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - } - break; - - case W_META_SAVEDC: - { - pOut->Push(); - } - break; - - case W_META_RESTOREDC: - { - pOut->Pop(); - } - break; - - case W_META_SETPIXEL: - { - const Color aColor = ReadColor(); - pOut->DrawPixel( ReadYX(), aColor ); - } - break; - - case W_META_OFFSETCLIPRGN: - { - pOut->MoveClipRegion( ReadYXExt() ); - } - break; - - case W_META_TEXTOUT: - { - sal_uInt16 nLength = 0; - pWMF->ReadUInt16( nLength ); - if ( nLength ) - { - std::unique_ptr<char[]> pChar(new char[ ( nLength + 1 ) &~ 1 ]); - pWMF->ReadBytes(pChar.get(), (nLength + 1) &~ 1); - OUString aText( pChar.get(), nLength, pOut->GetCharSet() ); - pChar.reset(); - Point aPosition( ReadYX() ); - pOut->DrawText( aPosition, aText ); - } - } - break; - - case W_META_EXTTEXTOUT: - { - pWMF->SeekRel(-6); - sal_Int32 nRecordPos = pWMF->Tell(), nRecordSize = 0; - pWMF->ReadInt32( nRecordSize ); - pWMF->SeekRel(2); - Point aPosition = ReadYX(); - sal_uInt16 nLen = 0, nOptions = 0; - pWMF->ReadUInt16( nLen ).ReadUInt16( nOptions ); - - ComplexTextLayoutFlags nTextLayoutMode = ComplexTextLayoutFlags::Default; - if ( nOptions & ETO_RTLREADING ) - nTextLayoutMode = ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::TextOriginLeft; - pOut->SetTextLayoutMode( nTextLayoutMode ); - SAL_WARN_IF( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) != 0, "vcl.wmf", "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" ); - - // output only makes sense if the text contains characters - if( nLen ) - { - sal_Int32 nOriginalTextLen = nLen; - sal_Int32 nOriginalBlockLen = ( nOriginalTextLen + 1 ) &~ 1; - tools::Rectangle aRect; - if( nOptions & ETO_CLIPPED ) - { - const Point aPt1( ReadPoint() ); - const Point aPt2( ReadPoint() ); - aRect = tools::Rectangle( aPt1, aPt2 ); - } - - auto nRemainingSize = pWMF->remainingSize(); - if (nRemainingSize < static_cast<sal_uInt32>(nOriginalBlockLen)) - { - SAL_WARN("vcl.wmf", "exttextout record claimed more data than the stream can provide"); - nOriginalTextLen = nOriginalBlockLen = nRemainingSize; - } - - std::unique_ptr<char[]> pChar(new char[nOriginalBlockLen]); - pWMF->ReadBytes(pChar.get(), nOriginalBlockLen); - OUString aText(pChar.get(), nOriginalTextLen, pOut->GetCharSet()); // after this conversion the text may contain - sal_Int32 nNewTextLen = aText.getLength(); // less character (japanese version), so the - // dxAry will not fit - if ( nNewTextLen ) - { - std::unique_ptr<long[]> pDXAry, pDYAry; - sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 ); - sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell(); - sal_Int32 nDxAryEntries = nDxArySize >> 1; - bool bUseDXAry = false; - - if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) - { - sal_Int32 i; // needed just outside the for - pDXAry.reset(new long[ nNewTextLen ]); - if ( nOptions & ETO_PDY ) - { - pDYAry.reset(new long[ nNewTextLen ]); - } - for (i = 0; i < nNewTextLen; i++ ) - { - if ( pWMF->Tell() >= nMaxStreamPos ) - break; - sal_Int32 nDxCount = 1; - if ( nNewTextLen != nOriginalTextLen ) - { - sal_Unicode cUniChar = aText[i]; - OString aTmp(&cUniChar, 1, pOut->GetCharSet()); - if ( aTmp.getLength() > 1 ) - { - nDxCount = aTmp.getLength(); - } - } - - sal_Int16 nDx = 0, nDy = 0; - while ( nDxCount-- ) - { - if ( ( pWMF->Tell() + 2 ) > nMaxStreamPos ) - break; - sal_Int16 nDxTmp = 0; - pWMF->ReadInt16(nDxTmp); - nDx += nDxTmp; - if ( nOptions & ETO_PDY ) - { - if ( ( pWMF->Tell() + 2 ) > nMaxStreamPos ) - break; - sal_Int16 nDyTmp = 0; - pWMF->ReadInt16(nDyTmp); - nDy += nDyTmp; - } - } - - pDXAry[ i ] = nDx; - if ( nOptions & ETO_PDY ) - { - pDYAry[i] = nDy; - } - } - if ( i == nNewTextLen ) - bUseDXAry = true; - } - if ( pDXAry && bUseDXAry ) - pOut->DrawText( aPosition, aText, pDXAry.get(), pDYAry.get() ); - else - pOut->DrawText( aPosition, aText ); - } - } - } - break; - - case W_META_SELECTOBJECT: - { - sal_Int16 nObjIndex = 0; - pWMF->ReadInt16( nObjIndex ); - pOut->SelectObject( nObjIndex ); - } - break; - - case W_META_SETTEXTALIGN: - { - sal_uInt16 nAlign = 0; - pWMF->ReadUInt16( nAlign ); - pOut->SetTextAlign( nAlign ); - } - break; - - case W_META_BITBLT: - { - // 0-3 : nWinROP #93454# - // 4-5 : y offset of source bitmap - // 6-7 : x offset of source bitmap - // 8-9 : used height of source bitmap - // 10-11 : used width of source bitmap - // 12-13 : destination position y (in pixel) - // 14-15 : destination position x (in pixel) - // 16-17 : don't know - // 18-19 : Width Bitmap in Pixel - // 20-21 : Height Bitmap in Pixel - // 22-23 : bytes per scanline - // 24 : planes - // 25 : bitcount - - sal_Int32 nWinROP = 0; - sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0; - sal_uInt8 nPlanes, nBitCount; - - pWMF->ReadInt32( nWinROP ) - .ReadUInt16( nSy ).ReadUInt16( nSx ).ReadUInt16( nSye ).ReadUInt16( nSxe ); - Point aPoint( ReadYX() ); - pWMF->ReadUInt16( nDontKnow ).ReadUInt16( nWidth ).ReadUInt16( nHeight ).ReadUInt16( nBytesPerScan ).ReadUChar( nPlanes ).ReadUChar( nBitCount ); - - bool bOk = nWidth && nHeight && nPlanes == 1 && nBitCount == 1; - if (bOk) - { - bOk = nBytesPerScan <= pWMF->remainingSize() / nHeight; - } - if (bOk) - { - Bitmap aBmp( Size( nWidth, nHeight ), nBitCount ); - Bitmap::ScopedWriteAccess pAcc(aBmp); - if ( pAcc ) - { - for (sal_uInt16 y = 0; y < nHeight && pWMF->good(); ++y) - { - sal_uInt16 x = 0; - for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ ) - { - sal_Int8 nEightPixels = 0; - pWMF->ReadSChar( nEightPixels ); - for (sal_Int8 i = 7; i >= 0; i-- ) - { - if ( x < nWidth ) - { - pAcc->SetPixelIndex( y, x, (nEightPixels>>i)&1 ); - } - x++; - } - } - } - pAcc.reset(); - if ( nSye && nSxe && - ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && - ( ( nSy + nSye ) <= aBmp.GetSizePixel().Height() ) ) - { - tools::Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); - aBmp.Crop( aCropRect ); - } - tools::Rectangle aDestRect( aPoint, Size( nSxe, nSye ) ); - aBmpSaveList.emplace_back(new BSaveStruct(aBmp, aDestRect, nWinROP)); - } - } - } - break; - - case W_META_STRETCHBLT: - case W_META_DIBBITBLT: - case W_META_DIBSTRETCHBLT: - case W_META_STRETCHDIB: - { - sal_Int32 nWinROP = 0; - sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0; - Bitmap aBmp; - - pWMF->ReadInt32( nWinROP ); - - if( nFunc == W_META_STRETCHDIB ) - pWMF->ReadUInt16( nUsage ); - - // nSye and nSxe is the number of pixels that has to been used - // If they are set to zero, it is as indicator not to scale the bitmap later - - if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT ) - pWMF->ReadUInt16( nSye ).ReadUInt16( nSxe ); - - // nSy and nx is the offset of the first pixel - pWMF->ReadUInt16( nSy ).ReadUInt16( nSx ); - - if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT ) - { - if ( nWinROP == PATCOPY ) - pWMF->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage - // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false ); - - Size aDestSize( ReadYXExt() ); - if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps - { - tools::Rectangle aDestRect( ReadYX(), aDestSize ); - if ( nWinROP != PATCOPY ) - ReadDIB(aBmp, *pWMF, false); - - // test if it is sensible to crop - if ( nSye && nSxe && - ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && - ( ( nSy + nSye ) <= aBmp.GetSizePixel().Height() ) ) - { - tools::Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); - aBmp.Crop( aCropRect ); - } - aBmpSaveList.emplace_back(new BSaveStruct(aBmp, aDestRect, nWinROP)); - } - } - } - break; - - case W_META_DIBCREATEPATTERNBRUSH: - { - Bitmap aBmp; - sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1; - sal_uInt16 nFunction = 0; - - pWMF->ReadUInt16( nFunction ).ReadUInt16( nFunction ); - - ReadDIB(aBmp, *pWMF, false); - Bitmap::ScopedReadAccess pBmp(aBmp); - if ( pBmp ) - { - for ( long y = 0; y < pBmp->Height(); y++ ) - { - for ( long x = 0; x < pBmp->Width(); x++ ) - { - const BitmapColor aColor( pBmp->GetColor( y, x ) ); - - nRed += aColor.GetRed(); - nGreen += aColor.GetGreen(); - nBlue += aColor.GetBlue(); - } - } - nCount = pBmp->Height() * pBmp->Width(); - if ( !nCount ) - nCount++; - pBmp.reset(); - } - Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) ); - pOut->CreateObject(o3tl::make_unique<WinMtfFillStyle>( aColor, false )); - } - break; - - case W_META_DELETEOBJECT: - { - sal_Int16 nIndex = 0; - pWMF->ReadInt16( nIndex ); - pOut->DeleteObject( nIndex ); - } - break; - - case W_META_CREATEPALETTE: - { - pOut->CreateObject(); - } - break; - - case W_META_CREATEBRUSH: - { - pOut->CreateObject(o3tl::make_unique<WinMtfFillStyle>( Color( COL_WHITE ), false )); - } - break; - - case W_META_CREATEPATTERNBRUSH: - { - pOut->CreateObject(o3tl::make_unique<WinMtfFillStyle>( Color( COL_WHITE ), false )); - } - break; - - case W_META_CREATEPENINDIRECT: - { - LineInfo aLineInfo; - sal_uInt16 nStyle = 0; - sal_uInt16 nWidth = 0; - sal_uInt16 nHeight = 0; - - pWMF->ReadUInt16(nStyle); - pWMF->ReadUInt16(nWidth); - pWMF->ReadUInt16(nHeight); - - if (nWidth > 0) - aLineInfo.SetWidth(nWidth); - - bool bTransparent = false; - - switch( nStyle & 0xFF ) - { - case PS_DASHDOTDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 2 ); - break; - case PS_DASHDOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DOT : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 0 ); - aLineInfo.SetDotCount( 1 ); - break; - case PS_DASH : - aLineInfo.SetStyle( LineStyle::Dash ); - aLineInfo.SetDashCount( 1 ); - aLineInfo.SetDotCount( 0 ); - break; - case PS_NULL : - bTransparent = true; - aLineInfo.SetStyle( LineStyle::NONE ); - break; - default : - case PS_INSIDEFRAME : - case PS_SOLID : - aLineInfo.SetStyle( LineStyle::Solid ); - } - switch( nStyle & 0xF00 ) - { - case PS_ENDCAP_ROUND : - aLineInfo.SetLineCap( css::drawing::LineCap_ROUND ); - break; - case PS_ENDCAP_SQUARE : - aLineInfo.SetLineCap( css::drawing::LineCap_SQUARE ); - break; - case PS_ENDCAP_FLAT : - default : - aLineInfo.SetLineCap( css::drawing::LineCap_BUTT ); - } - switch( nStyle & 0xF000 ) - { - case PS_JOIN_ROUND : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Round ); - break; - case PS_JOIN_MITER : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Miter ); - break; - case PS_JOIN_BEVEL : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::Bevel ); - break; - default : - aLineInfo.SetLineJoin ( basegfx::B2DLineJoin::NONE ); - } - pOut->CreateObject(o3tl::make_unique<WinMtfLineStyle>( ReadColor(), aLineInfo, bTransparent )); - } - break; - - case W_META_CREATEBRUSHINDIRECT: - { - sal_uInt16 nStyle = 0; - pWMF->ReadUInt16( nStyle ); - pOut->CreateObject(o3tl::make_unique<WinMtfFillStyle>( ReadColor(), ( nStyle == BS_HOLLOW ) )); - } - break; - - case W_META_CREATEFONTINDIRECT: - { - Size aFontSize; - char lfFaceName[LF_FACESIZE+1]; - sal_Int16 lfEscapement = 0; - sal_Int16 lfOrientation = 0; - sal_Int16 lfWeight = 0; - - LOGFONTW aLogFont; - unsigned char nTmp; - aFontSize = ReadYXExt(); - pWMF->ReadInt16( lfEscapement ); - pWMF->ReadInt16( lfOrientation ); - pWMF->ReadInt16( lfWeight ); - pWMF->ReadUChar( aLogFont.lfItalic ); - pWMF->ReadUChar( aLogFont.lfUnderline ); - pWMF->ReadUChar( aLogFont.lfStrikeOut ); - pWMF->ReadUChar( aLogFont.lfCharSet ); - pWMF->ReadUChar( nTmp ); // lfOutPrecision - pWMF->ReadUChar( nTmp ); // lfClipPrecision - pWMF->ReadUChar( nTmp ); // lfQuality - pWMF->ReadUChar( aLogFont.lfPitchAndFamily ); - size_t nRet = pWMF->ReadBytes( lfFaceName, LF_FACESIZE ); - lfFaceName[nRet] = 0; - aLogFont.lfWidth = aFontSize.Width(); - aLogFont.lfHeight = aFontSize.Height(); - aLogFont.lfEscapement = lfEscapement; - aLogFont.lfWeight = lfWeight; - - rtl_TextEncoding eCharSet; - if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) ) - eCharSet = osl_getThreadTextEncoding(); - else - eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet ); - if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) - eCharSet = osl_getThreadTextEncoding(); - if ( eCharSet == RTL_TEXTENCODING_SYMBOL ) - eCharSet = RTL_TEXTENCODING_MS_1252; - aLogFont.alfFaceName = OUString( lfFaceName, strlen(lfFaceName), eCharSet ); - - pOut->CreateObject(o3tl::make_unique<WinMtfFontStyle>( aLogFont )); - } - break; - - case W_META_CREATEBITMAPINDIRECT: - { - pOut->CreateObject(); - } - break; - - case W_META_CREATEBITMAP: - { - pOut->CreateObject(); - } - break; - - case W_META_CREATEREGION: - { - pOut->CreateObject(); - } - break; - - case W_META_EXCLUDECLIPRECT : - { - pOut->ExcludeClipRect( ReadRectangle() ); - } - break; - - case W_META_PATBLT: - { - sal_uInt32 nROP = 0; - WMFRasterOp nOldROP = WMFRasterOp::NONE; - pWMF->ReadUInt32( nROP ); - Size aSize = ReadYXExt(); - nOldROP = pOut->SetRasterOp( (WMFRasterOp)nROP ); - pOut->DrawRect( tools::Rectangle( ReadYX(), aSize ), false ); - pOut->SetRasterOp( nOldROP ); - } - break; - - case W_META_SELECTCLIPREGION: - { - sal_Int16 nObjIndex = 0; - pWMF->ReadInt16( nObjIndex ); - if ( !nObjIndex ) - { - tools::PolyPolygon aEmptyPolyPoly; - pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, true ); - } - } - break; - - case W_META_ESCAPE : - { - // nRecSize has been checked previously to be greater than 3 - sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2; - sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize; - - // taking care that nRecSize does not exceed the maximal stream position - if ( nMetaRecEndPos > nEndPos ) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - if ( nRecSize >= 4 ) // minimal escape length - { - sal_uInt16 nMode = 0, nLen = 0; - pWMF->ReadUInt16( nMode ) - .ReadUInt16( nLen ); - if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) - { - sal_uInt32 nNewMagic = 0; // we have to read int32 for - pWMF->ReadUInt32( nNewMagic ); // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier - - if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) - { - sal_uInt16 nMagic2 = 0; - pWMF->ReadUInt16( nMagic2 ); - if( nMagic2 == 0x0a ) // 2nd half of magic - { // continue with private escape - sal_uInt32 nCheck = 0, nEsc = 0; - pWMF->ReadUInt32( nCheck ) - .ReadUInt32( nEsc ); - - sal_uInt32 nEscLen = nLen - 14; - if ( nEscLen <= ( nRecSize * 2 ) ) - { -#ifdef OSL_BIGENDIAN - sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc ); - sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); -#else - sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); -#endif - std::unique_ptr<sal_Int8[]> pData; - - if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - break; - } - if ( nEscLen > 0 ) - { - pData.reset(new sal_Int8[ nEscLen ]); - pWMF->ReadBytes(pData.get(), nEscLen); - nCheckSum = rtl_crc32( nCheckSum, pData.get(), nEscLen ); - } - if ( nCheck == nCheckSum ) - { - switch( nEsc ) - { - case PRIVATE_ESCAPE_UNICODE : - { - // we will use text instead of polygons only if we have the correct font - if ( Application::GetDefaultDevice()->IsFontAvailable( pOut->GetFont().GetFamilyName() ) ) - { - Point aPt; - OUString aString; - sal_uInt32 nStringLen, nDXCount; - std::unique_ptr<long[]> pDXAry; - SvMemoryStream aMemoryStream( nEscLen ); - aMemoryStream.WriteBytes(pData.get(), nEscLen); - aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); - sal_Int32 nTmpX(0), nTmpY(0); - aMemoryStream.ReadInt32( nTmpX ) - .ReadInt32( nTmpY ) - .ReadUInt32( nStringLen ); - aPt.X() = nTmpX; - aPt.Y() = nTmpY; - - if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) - { - - aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen); - aMemoryStream.ReadUInt32( nDXCount ); - if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) - nDXCount = 0; - if ( nDXCount ) - pDXAry.reset(new long[ nDXCount ]); - for (sal_uInt32 i = 0; i < nDXCount; i++ ) - { - sal_Int32 val; - aMemoryStream.ReadInt32( val); - pDXAry[ i ] = val; - } - aMemoryStream.ReadUInt32( nSkipActions ); - pOut->DrawText( aPt, aString, pDXAry.get() ); - } - } - } - break; - } - } - } - } - } - else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) )) - { - sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0, - nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0; - sal_uInt16 nCheck = 0; - - pWMF->ReadUInt32( nComType ).ReadUInt32( nVersion ).ReadUInt16( nCheck ).ReadUInt32( nFlags ) - .ReadUInt32( nComRecCount ).ReadUInt32( nCurRecSize ) - .ReadUInt32( nRemainingSize ).ReadUInt32( nEMFTotalSize ); // the nRemainingSize is not mentioned in MSDN documentation - // but it seems to be required to read in data produced by OLE - - if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount ) - { - if( !nEMFRec ) - { // first EMF comment - nEMFRecCount = nComRecCount; - nEMFSize = nEMFTotalSize; - if (nEMFSize > pWMF->remainingSize()) - { - SAL_WARN("vcl.wmf", "emf size claims to be larger than remaining data"); - pEMFStream.reset(); - } - else - pEMFStream = o3tl::make_unique<SvMemoryStream>(nEMFSize, 0); - } - else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here - { - // total records should be the same as in previous comments - nEMFRecCount = 0xFFFFFFFF; - pEMFStream.reset(); - } - nEMFRec++; - - if (pEMFStream && nCurRecSize + 34 > nLen) - { - nEMFRecCount = 0xFFFFFFFF; - pEMFStream.reset(); - } - - if (pEMFStream && nCurRecSize > pWMF->remainingSize()) - { - SAL_WARN("vcl.wmf", "emf record size claims to be larger than remaining data"); - nEMFRecCount = 0xFFFFFFFF; - pEMFStream.reset(); - } - - if (pEMFStream) - { - std::vector<sal_Int8> aBuf(nCurRecSize); - sal_uInt32 nCount = pWMF->ReadBytes(aBuf.data(), nCurRecSize); - if( nCount == nCurRecSize ) - pEMFStream->WriteBytes(aBuf.data(), nCount); - } - } - } - } - } - } - break; - - case W_META_SETRELABS: - case W_META_SETPOLYFILLMODE: - case W_META_SETSTRETCHBLTMODE: - case W_META_SETTEXTCHAREXTRA: - case W_META_SETTEXTJUSTIFICATION: - case W_META_FLOODFILL : - case W_META_FILLREGION: - case W_META_FRAMEREGION: - case W_META_INVERTREGION: - case W_META_PAINTREGION: - case W_META_DRAWTEXT: - case W_META_SETMAPPERFLAGS: - case W_META_SETDIBTODEV: - case W_META_SELECTPALETTE: - case W_META_REALIZEPALETTE: - case W_META_ANIMATEPALETTE: - case W_META_SETPALENTRIES: - case W_META_RESIZEPALETTE: - case W_META_EXTFLOODFILL: - case W_META_RESETDC: - case W_META_STARTDOC: - case W_META_STARTPAGE: - case W_META_ENDPAGE: - case W_META_ABORTDOC: - case W_META_ENDDOC: - break; - } -} - -static const long aMaxWidth = 1024; - -bool WMFReader::ReadHeader() -{ - sal_uInt64 const nStrmPos = pWMF->Tell(); - - sal_uInt32 nPlaceableMetaKey(0); - // if available read the METAFILEHEADER - pWMF->ReadUInt32( nPlaceableMetaKey ); - if (!pWMF->good()) - return false; - - tools::Rectangle aPlaceableBound; - - bool bPlaceable = nPlaceableMetaKey == 0x9ac6cdd7L; - - SAL_INFO("vcl.wmf", "Placeable: \"" << (bPlaceable ? "yes" : "no") << "\""); - - if (bPlaceable) - { - //TODO do some real error handling here - sal_Int16 nVal; - - // Skip reserved bytes - pWMF->SeekRel(2); - - // BoundRect - pWMF->ReadInt16( nVal ); - aPlaceableBound.Left() = nVal; - pWMF->ReadInt16( nVal ); - aPlaceableBound.Top() = nVal; - pWMF->ReadInt16( nVal ); - aPlaceableBound.Right() = nVal; - pWMF->ReadInt16( nVal ); - aPlaceableBound.Bottom() = nVal; - - // inch - pWMF->ReadUInt16( nUnitsPerInch ); - - // reserved - pWMF->SeekRel( 4 ); - - // Skip and don't check the checksum - pWMF->SeekRel( 2 ); - } - else - { - nUnitsPerInch = 96; - - - if ( pExternalHeader != nullptr - && pExternalHeader->xExt > 0 - && pExternalHeader->yExt > 0 - && (pExternalHeader->mapMode == MM_ISOTROPIC || pExternalHeader->mapMode == MM_ANISOTROPIC)) - { - // #n417818#: If we have an external header then overwrite the bounds! - tools::Rectangle aExtRect(0, 0, - (double) pExternalHeader->xExt * 567 * nUnitsPerInch / 1440000, - (double) pExternalHeader->yExt * 567 * nUnitsPerInch / 1440000); - aPlaceableBound = aExtRect; - - SAL_INFO("vcl.wmf", "External header size " - " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top() - << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom()); - - pOut->SetMapMode( pExternalHeader->mapMode ); - } - else - { - pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the metaactions - GetPlaceableBound( aPlaceableBound, pWMF ); - - // The image size is not known so normalize the calculated bounds so that the - // resulting image is not too big - const double fMaxWidth = static_cast<double>(aMaxWidth); - if (aPlaceableBound.GetWidth() > aMaxWidth) - { - double fRatio = aPlaceableBound.GetWidth() / fMaxWidth; - - aPlaceableBound = tools::Rectangle( - aPlaceableBound.Left() / fRatio, - aPlaceableBound.Top() / fRatio, - aPlaceableBound.Right() / fRatio, - aPlaceableBound.Bottom() / fRatio); - - SAL_INFO("vcl.wmf", "Placeable bounds " - " t: " << aPlaceableBound.Left() << " l: " << aPlaceableBound.Top() - << " b: " << aPlaceableBound.Right() << " r: " << aPlaceableBound.Bottom()); - } - } - - pWMF->Seek( nStrmPos ); - } - - pOut->SetWinOrg( aPlaceableBound.TopLeft() ); - Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) ); - pOut->SetWinExt( aWMFSize ); - - SAL_INFO("vcl.wmf", "WMF size w: " << aWMFSize.Width() << " h: " << aWMFSize.Height()); - - Size aDevExt( 10000, 10000 ); - if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) ) - { - const Fraction aFrac( 1, nUnitsPerInch ); - MapMode aWMFMap( MapUnit::MapInch, Point(), aFrac, aFrac ); - Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MapUnit::Map100thMM ) ); - aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) ); - } - pOut->SetDevExt( aDevExt ); - - SAL_INFO("vcl.wmf", "Dev size w: " << aDevExt.Width() << " h: " << aDevExt.Height()); - - // read the METAHEADER - sal_uInt32 nMetaKey(0); - pWMF->ReadUInt32( nMetaKey ); // type and headersize - if (!pWMF->good()) - return false; - if (nMetaKey != 0x00090001) - { - sal_uInt16 aNextWord(0); - pWMF->ReadUInt16( aNextWord ); - if (nMetaKey != 0x10000 || aNextWord != 0x09) - { - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - return false; - } - } - - pWMF->SeekRel( 2 ); // Version (of Windows) - pWMF->SeekRel( 4 ); // Size (of file in words) - pWMF->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects) - pWMF->SeekRel( 4 ); // MaxRecord (size of largest record in words) - pWMF->SeekRel( 2 ); // NoParameters (Unused - - return pWMF->good(); -} - -void WMFReader::ReadWMF() -{ - sal_uInt16 nFunction; - sal_uLong nPos, nPercent, nLastPercent; - - nSkipActions = 0; - - pEMFStream.reset(); - nEMFRecCount = 0; - nEMFRec = 0; - nEMFSize = 0; - - pOut->SetMapMode( MM_ANISOTROPIC ); - pOut->SetWinOrg( Point() ); - pOut->SetWinExt( Size( 1, 1 ) ); - pOut->SetDevExt( Size( 10000, 10000 ) ); - - nEndPos=pWMF->Seek( STREAM_SEEK_TO_END ); - pWMF->Seek( nStartPos ); - Callback( (sal_uInt16) ( nLastPercent = 0 ) ); - - if ( ReadHeader( ) ) - { - nPos = pWMF->Tell(); - - if( nEndPos - nStartPos ) - { - bool bEMFAvailable = false; - while( true ) - { - nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos ); - - if( nLastPercent + 4 <= nPercent ) - { - Callback( (sal_uInt16) nPercent ); - nLastPercent = nPercent; - } - pWMF->ReadUInt32( nRecSize ).ReadUInt16( nFunction ); - - if( pWMF->GetError() - || ( nRecSize < 3 ) - || ( nRecSize == 3 - && nFunction == 0 - ) - || pWMF->IsEof() - ) - { - if( pWMF->IsEof() ) - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - - break; - } - if ( !bEMFAvailable ) - { - if( !aBmpSaveList.empty() - && ( nFunction != W_META_STRETCHDIB ) - && ( nFunction != W_META_DIBBITBLT ) - && ( nFunction != W_META_DIBSTRETCHBLT ) - ) - { - pOut->ResolveBitmapActions( aBmpSaveList ); - } - - if ( !nSkipActions ) - ReadRecordParams( nFunction ); - else - nSkipActions--; - - if( pEMFStream && nEMFRecCount == nEMFRec ) - { - GDIMetaFile aMeta; - pEMFStream->Seek( 0 ); - std::unique_ptr<EnhWMFReader> pEMFReader(o3tl::make_unique<EnhWMFReader>( *pEMFStream, aMeta )); - bEMFAvailable = pEMFReader->ReadEnhWMF(); - pEMFReader.reset(); // destroy first!!! - - if( bEMFAvailable ) - { - pOut->AddFromGDIMetaFile( aMeta ); - pOut->SetrclFrame( tools::Rectangle( Point(0, 0), aMeta.GetPrefSize())); - - // the stream needs to be set to the wmf end position, - // otherwise the GfxLink that is created will be incorrect - // (leading to graphic loss after swapout/swapin). - // so we will proceed normally, but are ignoring further wmf - // records - } - else - { - // something went wrong - // continue with WMF, don't try this again - pEMFStream.reset(); - } - } - } - const sal_uInt32 nAvailableBytes = nEndPos - nPos; - const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2; - if (nRecSize <= nMaxPossibleRecordSize) - { - nPos += nRecSize * 2; - pWMF->Seek(nPos); - } - else - pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); - } - } - else - pWMF->SetError( SVSTREAM_GENERALERROR ); - - if( !pWMF->GetError() && !aBmpSaveList.empty() ) - pOut->ResolveBitmapActions( aBmpSaveList ); - } - if ( pWMF->GetError() ) - pWMF->Seek( nStartPos ); -} - -void WMFReader::GetPlaceableBound( tools::Rectangle& rPlaceableBound, SvStream* pStm ) -{ - bool bRet = true; - - tools::Rectangle aBound; - aBound.Left() = RECT_MAX; - aBound.Top() = RECT_MAX; - aBound.Right() = RECT_MIN; - aBound.Bottom() = RECT_MIN; - bool bBoundsDetermined = false; - - sal_uInt32 nPos = pStm->Tell(); - sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END ); - - pStm->Seek( nPos ); - - Point aWinOrg(0,0); - boost::optional<Size> aWinExt; - - Point aViewportOrg(0,0); - boost::optional<Size> aViewportExt; - - if( nEnd - nPos ) - { - sal_Int16 nMapMode = MM_ANISOTROPIC; - sal_uInt16 nFunction; - sal_uInt32 nRSize; - - while( bRet ) - { - pStm->ReadUInt32( nRSize ).ReadUInt16( nFunction ); - - if( pStm->GetError() ) - { - bRet = false; - break; - } - else if ( nRSize==3 && nFunction==0 ) - { - break; - } - else if ( nRSize < 3 || pStm->IsEof() ) - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - break; - } - switch( nFunction ) - { - case W_META_SETWINDOWORG: - { - aWinOrg = ReadYX(); - } - break; - - case W_META_SETWINDOWEXT: - { - sal_Int16 nWidth(0), nHeight(0); - pStm->ReadInt16(nHeight); - pStm->ReadInt16(nWidth); - aWinExt = Size(nWidth, nHeight); - } - break; - - case W_META_SETVIEWPORTORG: - { - aViewportOrg = ReadYX(); - } - break; - - case W_META_SETVIEWPORTEXT: - { - sal_Int16 nWidth(0), nHeight(0); - pStm->ReadInt16(nHeight); - pStm->ReadInt16(nWidth); - aViewportExt = Size(nWidth, nHeight); - } - break; - - case W_META_SETMAPMODE : - pStm->ReadInt16( nMapMode ); - break; - - case W_META_MOVETO: - case W_META_LINETO: - GetWinExtMax( ReadYX(), aBound, nMapMode ); - bBoundsDetermined = true; - break; - - case W_META_RECTANGLE: - case W_META_INTERSECTCLIPRECT: - case W_META_EXCLUDECLIPRECT : - case W_META_ELLIPSE: - GetWinExtMax( ReadRectangle(), aBound, nMapMode ); - bBoundsDetermined = true; - break; - - case W_META_ROUNDRECT: - ReadYXExt(); // size - GetWinExtMax( ReadRectangle(), aBound, nMapMode ); - bBoundsDetermined = true; - break; - - case W_META_ARC: - case W_META_PIE: - case W_META_CHORD: - ReadYX(); // end - ReadYX(); // start - GetWinExtMax( ReadRectangle(), aBound, nMapMode ); - bBoundsDetermined = true; - break; - - case W_META_POLYGON: - { - bool bRecordOk = true; - - sal_uInt16 nPoints(0); - pStm->ReadUInt16( nPoints ); - - if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - } - else - { - for(sal_uInt16 i = 0; i < nPoints; i++ ) - { - GetWinExtMax( ReadPoint(), aBound, nMapMode ); - bBoundsDetermined = true; - } - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polyline record claimed more points than the stream can provide"); - - if (!bRecordOk) - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - break; - } - } - break; - - case W_META_POLYPOLYGON: - { - bool bRecordOk = true; - sal_uInt16 nPoly(0), nPoints(0); - pStm->ReadUInt16(nPoly); - if (nPoly > pStm->remainingSize() / sizeof(sal_uInt16)) - { - bRecordOk = false; - } - else - { - for(sal_uInt16 i = 0; i < nPoly; i++ ) - { - sal_uInt16 nP = 0; - pStm->ReadUInt16( nP ); - if (nP > SAL_MAX_UINT16 - nPoints) - { - bRecordOk = false; - break; - } - nPoints += nP; - } - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polypolygon record has more polygons than we can handle"); - - bRecordOk = bRecordOk && pStm->good(); - - if (!bRecordOk) - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - break; - } - - if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - } - else - { - for (sal_uInt16 i = 0; i < nPoints; i++ ) - { - GetWinExtMax( ReadPoint(), aBound, nMapMode ); - bBoundsDetermined = true; - } - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polypolygon record claimed more points than the stream can provide"); - - bRecordOk &= pStm->good(); - - if (!bRecordOk) - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - break; - } - } - break; - - case W_META_POLYLINE: - { - bool bRecordOk = true; - - sal_uInt16 nPoints(0); - pStm->ReadUInt16(nPoints); - if (nPoints > pStm->remainingSize() / (2 * sizeof(sal_uInt16))) - { - bRecordOk = false; - } - else - { - for (sal_uInt16 i = 0; i < nPoints; ++i) - { - GetWinExtMax( ReadPoint(), aBound, nMapMode ); - bBoundsDetermined = true; - } - } - - SAL_WARN_IF(!bRecordOk, "vcl.wmf", "polyline record claimed more points than the stream can provide"); - - if (!bRecordOk) - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - break; - } - } - break; - - case W_META_SETPIXEL: - { - ReadColor(); - GetWinExtMax( ReadYX(), aBound, nMapMode ); - bBoundsDetermined = true; - } - break; - - case W_META_TEXTOUT: - { - sal_uInt16 nLength; - pStm->ReadUInt16( nLength ); - // todo: we also have to take care of the text width - if ( nLength ) - { - pStm->SeekRel( ( nLength + 1 ) &~ 1 ); - GetWinExtMax( ReadYX(), aBound, nMapMode ); - bBoundsDetermined = true; - } - } - break; - - case W_META_EXTTEXTOUT: - { - sal_uInt16 nLen, nOptions; - Point aPosition; - - aPosition = ReadYX(); - pStm->ReadUInt16( nLen ).ReadUInt16( nOptions ); - // todo: we also have to take care of the text width - if( nLen ) - { - GetWinExtMax( aPosition, aBound, nMapMode ); - bBoundsDetermined = true; - } - } - break; - case W_META_BITBLT: - case W_META_STRETCHBLT: - case W_META_DIBBITBLT: - case W_META_DIBSTRETCHBLT: - case W_META_STRETCHDIB: - { - sal_Int32 nWinROP; - sal_uInt16 nSx, nSy, nUsage; - pStm->ReadInt32( nWinROP ); - - if( nFunction == W_META_STRETCHDIB ) - pStm->ReadUInt16( nUsage ); - - // nSye and nSxe is the number of pixels that has to been used - if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT ) - { - sal_uInt16 nSxe, nSye; - pStm->ReadUInt16( nSye ).ReadUInt16( nSxe ); - } - - // nSy and nx is the offset of the first pixel - pStm->ReadUInt16( nSy ).ReadUInt16( nSx ); - - if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT ) - { - if ( nWinROP == PATCOPY ) - pStm->ReadUInt16( nUsage ); // i don't know anything of this parameter, so its called nUsage - // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), false ); - - Size aDestSize( ReadYXExt() ); - if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps - { - tools::Rectangle aDestRect( ReadYX(), aDestSize ); - GetWinExtMax( aDestRect, aBound, nMapMode ); - bBoundsDetermined = true; - } - } - } - break; - - case W_META_PATBLT: - { - sal_uInt32 nROP; - pStm->ReadUInt32( nROP ); - Size aSize = ReadYXExt(); - GetWinExtMax( tools::Rectangle( ReadYX(), aSize ), aBound, nMapMode ); - bBoundsDetermined = true; - } - break; - } - - const sal_uInt32 nAvailableBytes = nEnd - nPos; - const sal_uInt32 nMaxPossibleRecordSize = nAvailableBytes/2; - if (nRSize <= nMaxPossibleRecordSize) - { - nPos += nRSize * 2; - pStm->Seek( nPos ); - } - else - { - pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); - bRet = false; - } - } - } - else - { - pStm->SetError( SVSTREAM_GENERALERROR ); - bRet = false; - } - - if (bRet) - { - if (aWinExt) - { - rPlaceableBound = tools::Rectangle(aWinOrg, *aWinExt); - SAL_INFO("vcl.wmf", "Window dimension " - " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top() - << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom()); - } - else if (aViewportExt) - { - rPlaceableBound = tools::Rectangle(aViewportOrg, *aViewportExt); - SAL_INFO("vcl.wmf", "Viewport dimension " - " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top() - << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom()); - } - else if (bBoundsDetermined) - { - rPlaceableBound = aBound; - SAL_INFO("vcl.wmf", "Determined dimension " - " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top() - << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom()); - } - else - { - rPlaceableBound.Left() = 0; - rPlaceableBound.Top() = 0; - rPlaceableBound.Right() = aMaxWidth; - rPlaceableBound.Bottom() = aMaxWidth; - SAL_INFO("vcl.wmf", "Default dimension " - " t: " << rPlaceableBound.Left() << " l: " << rPlaceableBound.Top() - << " b: " << rPlaceableBound.Right() << " r: " << rPlaceableBound.Bottom()); - } - } -} - -WMFReader::WMFReader(SvStream& rStreamWMF, GDIMetaFile& rGDIMetaFile, - FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER* pExtHeader) - : WinMtf(rGDIMetaFile, rStreamWMF, pConfigItem) - , nUnitsPerInch(96) - , nRecSize(0) - , nEMFRecCount(0) - , nEMFRec(0) - , nEMFSize(0) - , nSkipActions(0) - , pExternalHeader(pExtHeader) -{} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx index ad9d1536d1d5..f620a8e00303 100644 --- a/vcl/source/filter/wmf/wmf.cxx +++ b/vcl/source/filter/wmf/wmf.cxx @@ -17,65 +17,38 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include "winmtf.hxx" #include "emfwr.hxx" #include "wmfwr.hxx" #include <vcl/wmf.hxx> #include <vcl/gdimetafiletools.hxx> #include <comphelper/scopeguard.hxx> -bool ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER *pExtHeader ) -{ - sal_uInt32 nMetaType; - sal_uInt32 nOrgPos = rStreamWMF.Tell(); - SvStreamEndian nOrigNumberFormat = rStreamWMF.GetEndian(); - rStreamWMF.SetEndian( SvStreamEndian::LITTLE ); - rStreamWMF.Seek( 0x28 ); - rStreamWMF.ReadUInt32( nMetaType ); - rStreamWMF.Seek( nOrgPos ); - if ( nMetaType == 0x464d4520 ) - { - if ( !EnhWMFReader( rStreamWMF, rGDIMetaFile, pConfigItem ).ReadEnhWMF() ) - rStreamWMF.SetError( SVSTREAM_FILEFORMAT_ERROR ); - } - else - { - WMFReader( rStreamWMF, rGDIMetaFile, pConfigItem, pExtHeader ).ReadWMF( ); - } - - // #i123216# allow a look at CheckSum and ByteSize for debugging - SAL_INFO("vcl.emf", "\t\t\tchecksum: 0x" << std::hex << rGDIMetaFile.GetChecksum() << std::dec); - SAL_INFO("vcl.emf", "\t\t\tsize: " << rGDIMetaFile.GetSizeBytes()); - - rStreamWMF.SetEndian( nOrigNumberFormat ); - return !rStreamWMF.GetError(); -} - bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF ) { - sal_uInt32 nMetaType(0); - sal_uInt32 nOrgPos = rStream.Tell(); - - SvStreamEndian nOrigNumberFormat = rStream.GetEndian(); - rStream.SetEndian( SvStreamEndian::LITTLE ); - //exception-safe reset nOrigNumberFormat at end of scope - const ::comphelper::ScopeGuard aScopeGuard( [&rStream, nOrigNumberFormat] () { rStream.SetEndian( nOrigNumberFormat ); } ); - - rStream.Seek( 0x28 ); - rStream.ReadUInt32( nMetaType ); - rStream.Seek( nOrgPos ); - - if (!rStream.good()) - return false; - - if ( nMetaType == 0x464d4520 ) - { - if ( !EnhWMFReader( rStream, rMTF, nullptr ).ReadEnhWMF() ) - rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); - } - else + // Use new method to import Metafile. First, read binary data to mem array + const sal_uInt32 nStreamLength(rStream.Seek(STREAM_SEEK_TO_END)); + VectorGraphicDataArray aNewData(nStreamLength); + rStream.Seek(0); + rStream.ReadBytes(aNewData.begin(), nStreamLength); + rStream.Seek(0); + + if (rStream.good()) { - WMFReader( rStream, rMTF, nullptr ).ReadWMF(); + // Throw into VectorGraphicData to get the import. Do not care + // too much for type, this will be checked there. Also no path + // needed, it is a temporary object + VectorGraphicDataPtr aVectorGraphicDataPtr( + new VectorGraphicData( + aNewData, + OUString(), + VectorGraphicDataType::Emf)); + + // create a Graphic and grep Metafile from it + const Graphic aGraphic(aVectorGraphicDataPtr); + + // get the Metafile from it, done + rMTF = aGraphic.GetGDIMetaFile(); + return true; } return rStream.good(); diff --git a/vcl/source/filter/wmf/wmfexternal.cxx b/vcl/source/filter/wmf/wmfexternal.cxx new file mode 100644 index 000000000000..eda806a3d113 --- /dev/null +++ b/vcl/source/filter/wmf/wmfexternal.cxx @@ -0,0 +1,76 @@ +/* -*- 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 <vcl/wmfexternal.hxx> + +// formally known as WMF_EXTERNALHEADER +WmfExternal::WmfExternal() : + xExt(0), + yExt(0), + mapMode(0) +{ +} + +css::uno::Sequence< css::beans::PropertyValue > WmfExternal::getSequence() const +{ + css::uno::Sequence< css::beans::PropertyValue > aSequence; + + if (0 != xExt || 0 != yExt || 0 != mapMode) + { + aSequence.realloc(3); + aSequence[0].Name = "Width"; + aSequence[0].Value <<= (sal_Int16)xExt; + aSequence[1].Name = "Height"; + aSequence[1].Value <<= (sal_Int16)yExt; + aSequence[2].Name = "MapMode"; + aSequence[2].Value <<= (sal_Int16)mapMode; + } + + return aSequence; +} + +bool WmfExternal::setSequence(const css::uno::Sequence< css::beans::PropertyValue >& rSequence) +{ + bool bRetval(false); + + for (sal_Int32 i = 0; i < rSequence.getLength(); ++i) + { + const OUString aName(rSequence[i].Name); + + if (aName == "Width") + { + rSequence[i].Value >>= xExt; + bRetval = true; + } + else if (aName == "Height") + { + rSequence[i].Value >>= yExt; + bRetval = true; + } + else if (aName == "MapMode") + { + rSequence[i].Value >>= mapMode; + bRetval = true; + } + } + + return bRetval; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index 14ccf012b765..486a4012c54a 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -39,6 +39,7 @@ #include <vcl/dibtools.hxx> #include <memory> #include <o3tl/make_unique.hxx> +#include <vcl/gdimetafiletools.hxx> #define GRAPHIC_MTFTOBMP_MAXEXT 2048 #define GRAPHIC_STREAMBUFSIZE 8192UL @@ -584,6 +585,32 @@ const BitmapEx& ImpGraphic::ImplGetBitmapExRef() const const GDIMetaFile& ImpGraphic::ImplGetGDIMetaFile() const { + if (!maMetaFile.GetActionSize() + && maVectorGraphicData.get() + && (VectorGraphicDataType::Emf == maVectorGraphicData->getVectorGraphicDataType() + || VectorGraphicDataType::Wmf == maVectorGraphicData->getVectorGraphicDataType())) + { + // 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]); + const MetafileAccessor* pMetafileAccessor = dynamic_cast< const MetafileAccessor* >(xReference.get()); + + if (pMetafileAccessor) + { + // it is a MetafileAccessor implementation, get Metafile + pMetafileAccessor->accessMetafile(const_cast< ImpGraphic* >(this)->maMetaFile); + } + } + } + if (GraphicType::Bitmap == meType && !maMetaFile.GetActionSize()) { // #i119735# diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx index d68cb80333ad..84673ba6a547 100644 --- a/vcl/source/gdi/vectorgraphicdata.cxx +++ b/vcl/source/gdi/vectorgraphicdata.cxx @@ -125,6 +125,16 @@ bool VectorGraphicData::operator==(const VectorGraphicData& rCandidate) const return false; } +void VectorGraphicData::setWmfExternalHeader(const WmfExternal& aExtHeader) +{ + if (!mpExternalHeader) + { + mpExternalHeader = new WmfExternal; + } + + *mpExternalHeader = aExtHeader; +} + void VectorGraphicData::ensureReplacement() { ensureSequenceAndRange(); @@ -156,8 +166,14 @@ void VectorGraphicData::ensureSequenceAndRange() || VectorGraphicDataType::Wmf == getVectorGraphicDataType()) { const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext); + uno::Sequence< ::beans::PropertyValue > aSequence; - maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(myInputStream, maPath)); + if (mpExternalHeader) + { + aSequence = mpExternalHeader->getSequence(); + } + + maSequence = comphelper::sequenceToContainer<std::deque<css::uno::Reference< css::graphic::XPrimitive2D >>>(xEmfParser->getDecomposition(myInputStream, maPath, aSequence)); } else { @@ -222,7 +238,8 @@ VectorGraphicData::VectorGraphicData( maSequence(), maReplacement(), mNestedBitmapSize(0), - meVectorGraphicDataType(eVectorDataType) + meVectorGraphicDataType(eVectorDataType), + mpExternalHeader(nullptr) { } @@ -235,7 +252,8 @@ VectorGraphicData::VectorGraphicData( maSequence(), maReplacement(), mNestedBitmapSize(0), - meVectorGraphicDataType(eVectorDataType) + meVectorGraphicDataType(eVectorDataType), + mpExternalHeader(nullptr) { SvFileStream rIStm(rPath, StreamMode::STD_READ); if(rIStm.GetError()) @@ -253,6 +271,14 @@ VectorGraphicData::VectorGraphicData( } } +VectorGraphicData::~VectorGraphicData() +{ + if (mpExternalHeader) + { + delete mpExternalHeader; + }; +} + const basegfx::B2DRange& VectorGraphicData::getRange() const { const_cast< VectorGraphicData* >(this)->ensureSequenceAndRange(); diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx index b42e589e7ab5..a8ab5b325547 100644 --- a/writerfilter/source/rtftok/rtfdocumentimpl.cxx +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -828,11 +828,11 @@ void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XS // Store, and get its URL. pStream->Seek(0); uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream)); - WMF_EXTERNALHEADER aExtHeader; + WmfExternal aExtHeader; aExtHeader.mapMode = m_aStates.top().aPicture.eWMetafile; aExtHeader.xExt = m_aStates.top().aPicture.nWidth; aExtHeader.yExt = m_aStates.top().aPicture.nHeight; - WMF_EXTERNALHEADER* pExtHeader = &aExtHeader; + WmfExternal* pExtHeader = &aExtHeader; uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().aDrawingObject.xShape, uno::UNO_QUERY); if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame")) pExtHeader = nullptr; diff --git a/xmlsecurity/workben/pdfverify.cxx b/xmlsecurity/workben/pdfverify.cxx index 7b369709201c..8a14f7bf3402 100644 --- a/xmlsecurity/workben/pdfverify.cxx +++ b/xmlsecurity/workben/pdfverify.cxx @@ -37,7 +37,7 @@ void generatePreview(const OString& rPdfPath, const OString& rPngPath) OUString aInURL; osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(rPdfPath), aInURL); SvFileStream aInStream(aInURL, StreamMode::READ); - WMF_EXTERNALHEADER* pExtHeader = nullptr; + WmfExternal* pExtHeader = nullptr; if (rFilter.ImportGraphic(aGraphic, OUString(), aInStream, GRFILTER_FORMAT_DONTKNOW, nullptr, GraphicFilterImportFlags::NONE, pExtHeader) != ERRCODE_NONE) return; |