summaryrefslogtreecommitdiffstats
path: root/vcl/source/filter/svm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/source/filter/svm
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/filter/svm')
-rw-r--r--vcl/source/filter/svm/SvmConverter.cxx1290
-rw-r--r--vcl/source/filter/svm/SvmConverter.hxx92
-rw-r--r--vcl/source/filter/svm/SvmReader.cxx1438
-rw-r--r--vcl/source/filter/svm/SvmWriter.cxx1421
4 files changed, 4241 insertions, 0 deletions
diff --git a/vcl/source/filter/svm/SvmConverter.cxx b/vcl/source/filter/svm/SvmConverter.cxx
new file mode 100644
index 000000000..2e7ed8f35
--- /dev/null
+++ b/vcl/source/filter/svm/SvmConverter.cxx
@@ -0,0 +1,1290 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <osl/thread.h>
+#include <tools/fract.hxx>
+#include <tools/stream.hxx>
+#include <o3tl/safeint.hxx>
+
+#include <vcl/TypeSerializer.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/virdev.hxx>
+
+#include "SvmConverter.hxx"
+
+#include <boost/rational.hpp>
+#include <algorithm>
+#include <memory>
+#include <stack>
+#include <string.h>
+
+// Inlines
+static void ImplReadRect( SvStream& rIStm, tools::Rectangle& rRect )
+{
+ Point aTL;
+ Point aBR;
+
+ TypeSerializer aSerializer(rIStm);
+ aSerializer.readPoint(aTL);
+ aSerializer.readPoint(aBR);
+
+ rRect = tools::Rectangle( aTL, aBR );
+}
+
+static bool ImplReadPoly(SvStream& rIStm, tools::Polygon& rPoly)
+{
+ TypeSerializer aSerializer(rIStm);
+
+ sal_Int32 nSize32(0);
+ rIStm.ReadInt32(nSize32);
+ sal_uInt16 nSize = nSize32;
+
+ const size_t nMaxPossiblePoints = rIStm.remainingSize() / 2 * sizeof(sal_Int32);
+ if (nSize > nMaxPossiblePoints)
+ {
+ SAL_WARN("vcl.gdi", "svm record claims to have: " << nSize << " points, but only " << nMaxPossiblePoints << " possible");
+ return false;
+ }
+
+ rPoly = tools::Polygon(nSize);
+
+ for (sal_uInt16 i = 0; i < nSize && rIStm.good(); ++i)
+ {
+ aSerializer.readPoint(rPoly[i]);
+ }
+ return rIStm.good();
+}
+
+static bool ImplReadPolyPoly(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
+{
+ bool bSuccess = true;
+
+ tools::Polygon aPoly;
+ sal_Int32 nPolyCount32(0);
+ rIStm.ReadInt32(nPolyCount32);
+ sal_uInt16 nPolyCount = static_cast<sal_uInt16>(nPolyCount32);
+
+ for (sal_uInt16 i = 0; i < nPolyCount && rIStm.good(); ++i)
+ {
+ if (!ImplReadPoly(rIStm, aPoly))
+ {
+ bSuccess = false;
+ break;
+ }
+ rPolyPoly.Insert(aPoly);
+ }
+
+ return bSuccess && rIStm.good();
+}
+
+static void ImplReadColor( SvStream& rIStm, Color& rColor )
+{
+ sal_Int16 nVal(0);
+
+ rIStm.ReadInt16( nVal ); rColor.SetRed( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
+ rIStm.ReadInt16( nVal ); rColor.SetGreen( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
+ rIStm.ReadInt16( nVal ); rColor.SetBlue( sal::static_int_cast<sal_uInt8>(static_cast<sal_uInt16>(nVal) >> 8) );
+}
+
+static bool ImplReadMapMode(SvStream& rIStm, MapMode& rMapMode)
+{
+ sal_Int16 nUnit(0);
+ rIStm.ReadInt16(nUnit);
+
+ Point aOrg;
+ TypeSerializer aSerializer(rIStm);
+ aSerializer.readPoint(aOrg);
+
+ sal_Int32 nXNum(0), nXDenom(0), nYNum(0), nYDenom(0);
+ rIStm.ReadInt32(nXNum).ReadInt32(nXDenom).ReadInt32(nYNum).ReadInt32(nYDenom);
+
+ if (!rIStm.good() || nXDenom <= 0 || nYDenom <= 0 || nXNum <= 0 || nYNum <= 0)
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode fraction");
+ return false;
+ }
+
+ if (nUnit < sal_Int16(MapUnit::Map100thMM) || nUnit > sal_Int16(MapUnit::LAST))
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: invalid mapmode");
+ return false;
+ }
+
+ rMapMode = MapMode(static_cast<MapUnit>(nUnit), aOrg, Fraction(nXNum, nXDenom), Fraction(nYNum, nYDenom));
+
+ return true;
+}
+
+static void ImplReadUnicodeComment( sal_uInt32 nStrmPos, SvStream& rIStm, OUString& rString )
+{
+ sal_uInt64 nOld = rIStm.Tell();
+ if ( nStrmPos )
+ {
+ sal_uInt16 nType;
+ sal_uInt32 nActionSize;
+ std::size_t nStringLen;
+
+ rIStm.Seek( nStrmPos );
+ rIStm .ReadUInt16( nType )
+ .ReadUInt32( nActionSize );
+
+ nStringLen = (nActionSize - 4) >> 1;
+
+ if ( nStringLen && ( nType == GDI_UNICODE_COMMENT ) )
+ rString = read_uInt16s_ToOUString(rIStm, nStringLen);
+ }
+ rIStm.Seek( nOld );
+}
+
+static void ImplSkipActions(SvStream& rIStm, sal_uLong nSkipCount)
+{
+ sal_Int32 nActionSize;
+ sal_Int16 nType;
+ for (sal_uLong i = 0; i < nSkipCount; ++i)
+ {
+ rIStm.ReadInt16(nType).ReadInt32(nActionSize);
+ if (!rIStm.good() || nActionSize < 4)
+ break;
+ rIStm.SeekRel(nActionSize - 4);
+ }
+}
+
+static void ImplReadExtendedPolyPolygonAction(SvStream& rIStm, tools::PolyPolygon& rPolyPoly)
+{
+ TypeSerializer aSerializer(rIStm);
+
+ rPolyPoly.Clear();
+ sal_uInt16 nPolygonCount(0);
+ rIStm.ReadUInt16( nPolygonCount );
+
+ if (!nPolygonCount)
+ return;
+
+ const size_t nMinRecordSize = sizeof(sal_uInt16);
+ const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
+ if (nPolygonCount > nMaxRecords)
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
+ " max possible entries, but " << nPolygonCount << " claimed, truncating");
+ nPolygonCount = nMaxRecords;
+ }
+
+ for(sal_uInt16 a(0); a < nPolygonCount; a++)
+ {
+ sal_uInt16 nPointCount(0);
+ rIStm.ReadUInt16(nPointCount);
+
+ const size_t nMinPolygonSize = sizeof(sal_Int32) * 2;
+ const size_t nMaxPolygons = rIStm.remainingSize() / nMinPolygonSize;
+ if (nPointCount > nMaxPolygons)
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: " << nMaxPolygons <<
+ " max possible entries, but " << nPointCount << " claimed, truncating");
+ nPointCount = nMaxPolygons;
+ }
+
+ tools::Polygon aCandidate(nPointCount);
+
+ if (nPointCount)
+ {
+ for(sal_uInt16 b(0); b < nPointCount; b++)
+ {
+ aSerializer.readPoint(aCandidate[b]);
+ }
+
+ sal_uInt8 bHasFlags(int(false));
+ rIStm.ReadUChar( bHasFlags );
+
+ if(bHasFlags)
+ {
+ sal_uInt8 aPolyFlags(0);
+
+ for(sal_uInt16 c(0); c < nPointCount; c++)
+ {
+ rIStm.ReadUChar( aPolyFlags );
+ aCandidate.SetFlags(c, static_cast<PolyFlags>(aPolyFlags));
+ }
+ }
+ }
+
+ rPolyPoly.Insert(aCandidate);
+ }
+}
+
+SVMConverter::SVMConverter( SvStream& rStm, GDIMetaFile& rMtf )
+{
+ if( !rStm.GetError() )
+ {
+ ImplConvertFromSVM1( rStm, rMtf );
+ }
+}
+
+namespace
+{
+ sal_Int32 SkipActions(sal_Int32 i, sal_Int32 nFollowingActionCount, sal_Int32 nActions)
+ {
+ sal_Int32 remainingActions = nActions - i;
+ if (nFollowingActionCount < 0)
+ nFollowingActionCount = remainingActions;
+ return std::min(remainingActions, nFollowingActionCount);
+ }
+
+ void ClampRange(const OUString& rStr, sal_Int32& rIndex, sal_Int32& rLength,
+ std::vector<sal_Int32>* pDXAry = nullptr)
+ {
+ const sal_Int32 nStrLength = rStr.getLength();
+
+ if (rIndex < 0 || rIndex > nStrLength)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent offset");
+ rIndex = nStrLength;
+ }
+
+ if (rLength < 0 || rLength > nStrLength - rIndex)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent len");
+ rLength = nStrLength - rIndex;
+ }
+
+ if (pDXAry && pDXAry->size() > o3tl::make_unsigned(rLength))
+ pDXAry->resize(rLength);
+ }
+}
+
+#define LF_FACESIZE 32
+
+void static lcl_error( SvStream& rIStm, const SvStreamEndian& nOldFormat, sal_uInt64 nPos)
+{
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ rIStm.SetEndian(nOldFormat);
+ rIStm.Seek(nPos);
+ return;
+}
+void SVMConverter::ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf )
+{
+ const sal_uInt64 nPos = rIStm.Tell();
+ const SvStreamEndian nOldFormat = rIStm.GetEndian();
+
+ rIStm.SetEndian( SvStreamEndian::LITTLE );
+
+ char aCode[ 5 ];
+ Size aPrefSz;
+
+ // read header
+ rIStm.ReadBytes(aCode, sizeof(aCode)); // Identifier
+ sal_Int16 nSize(0);
+ rIStm.ReadInt16( nSize ); // Size
+ sal_Int16 nVersion(0);
+ rIStm.ReadInt16( nVersion ); // Version
+ sal_Int32 nTmp32(0);
+ rIStm.ReadInt32( nTmp32 );
+ if (nTmp32 < 0)
+ {
+ SAL_WARN("vcl.gdi", "svm: value for width should be positive");
+ lcl_error(rIStm, nOldFormat, nPos);
+ return;
+ }
+ aPrefSz.setWidth( nTmp32 ); // PrefSize.Width()
+ rIStm.ReadInt32( nTmp32 );
+ if (nTmp32 < 0)
+ {
+ SAL_WARN("vcl.gdi", "svm: value for height should be positive");
+ lcl_error(rIStm, nOldFormat, nPos);
+ return;
+ }
+ aPrefSz.setHeight( nTmp32 ); // PrefSize.Height()
+
+ // check header-magic and version
+ if( rIStm.GetError()
+ || ( nVersion != 200 )
+ || ( memcmp( aCode, "SVGDI", sizeof( aCode ) ) != 0 ) )
+ {
+ SAL_WARN("vcl.gdi", "svm: wrong check for header-magic and version");
+ lcl_error(rIStm, nOldFormat, nPos);
+ return;
+ }
+
+ LineInfo aLineInfo( LineStyle::NONE, 0 );
+ std::stack<LineInfo, std::vector<LineInfo>> aLIStack;
+ ScopedVclPtrInstance< VirtualDevice > aFontVDev;
+ rtl_TextEncoding eActualCharSet = osl_getThreadTextEncoding();
+ bool bFatLine = false;
+
+ tools::Polygon aActionPoly;
+ tools::Rectangle aRect;
+ Point aPt, aPt1;
+ Size aSz;
+ Color aActionColor;
+
+ sal_uInt32 nUnicodeCommentStreamPos = 0;
+ sal_Int32 nUnicodeCommentActionNumber = 0;
+
+ rMtf.SetPrefSize(aPrefSz);
+
+ MapMode aMapMode;
+ if (ImplReadMapMode(rIStm, aMapMode)) // MapMode
+ rMtf.SetPrefMapMode(aMapMode);
+
+ sal_Int32 nActions(0);
+ rIStm.ReadInt32(nActions); // Action count
+ if (nActions < 0)
+ {
+ SAL_WARN("vcl.gdi", "svm claims negative action count (" << nActions << ")");
+ nActions = 0;
+ }
+
+ const size_t nMinActionSize = sizeof(sal_uInt16) + sizeof(sal_Int32);
+ const size_t nMaxPossibleActions = rIStm.remainingSize() / nMinActionSize;
+ if (o3tl::make_unsigned(nActions) > nMaxPossibleActions)
+ {
+ SAL_WARN("vcl.gdi", "svm claims more actions (" << nActions << ") than stream could provide, truncating");
+ nActions = nMaxPossibleActions;
+ }
+
+ size_t nLastPolygonAction(0);
+
+ TypeSerializer aSerializer(rIStm);
+
+ for (sal_Int32 i = 0; i < nActions && rIStm.good(); ++i)
+ {
+ sal_Int16 nType(0);
+ rIStm.ReadInt16(nType);
+ sal_Int32 nActBegin = rIStm.Tell();
+ sal_Int32 nActionSize(0);
+ rIStm.ReadInt32(nActionSize);
+
+ SAL_WARN_IF( ( nType > 33 ) && ( nType < 1024 ), "vcl.gdi", "Unknown GDIMetaAction while converting!" );
+
+ switch( nType )
+ {
+ case GDI_PIXEL_ACTION:
+ {
+ aSerializer.readPoint(aPt);
+ ImplReadColor( rIStm, aActionColor );
+ rMtf.AddAction( new MetaPixelAction( aPt, aActionColor ) );
+ }
+ break;
+
+ case GDI_POINT_ACTION:
+ {
+ aSerializer.readPoint(aPt);
+ rMtf.AddAction( new MetaPointAction( aPt ) );
+ }
+ break;
+
+ case GDI_LINE_ACTION:
+ {
+ aSerializer.readPoint(aPt);
+ aSerializer.readPoint(aPt1);
+ rMtf.AddAction( new MetaLineAction( aPt, aPt1, aLineInfo ) );
+ }
+ break;
+
+ case GDI_LINEJOIN_ACTION :
+ {
+ sal_Int16 nLineJoin(0);
+ rIStm.ReadInt16( nLineJoin );
+ aLineInfo.SetLineJoin(static_cast<basegfx::B2DLineJoin>(nLineJoin));
+ }
+ break;
+
+ case GDI_LINECAP_ACTION :
+ {
+ sal_Int16 nLineCap(0);
+ rIStm.ReadInt16( nLineCap );
+ aLineInfo.SetLineCap(static_cast<css::drawing::LineCap>(nLineCap));
+ }
+ break;
+
+ case GDI_LINEDASHDOT_ACTION :
+ {
+ sal_Int16 a(0);
+ sal_Int32 b(0);
+
+ rIStm.ReadInt16( a ); aLineInfo.SetDashCount(a);
+ rIStm.ReadInt32( b ); aLineInfo.SetDashLen(b);
+ rIStm.ReadInt16( a ); aLineInfo.SetDotCount(a);
+ rIStm.ReadInt32( b ); aLineInfo.SetDotLen(b);
+ rIStm.ReadInt32( b ); aLineInfo.SetDistance(b);
+
+ if(((aLineInfo.GetDashCount() && aLineInfo.GetDashLen())
+ || (aLineInfo.GetDotCount() && aLineInfo.GetDotLen()))
+ && aLineInfo.GetDistance())
+ {
+ aLineInfo.SetStyle(LineStyle::Dash);
+ }
+ }
+ break;
+
+ case GDI_EXTENDEDPOLYGON_ACTION :
+ {
+ // read the tools::PolyPolygon in every case
+ tools::PolyPolygon aInputPolyPolygon;
+ ImplReadExtendedPolyPolygonAction(rIStm, aInputPolyPolygon);
+
+ // now check if it can be set somewhere
+ if(nLastPolygonAction < rMtf.GetActionSize())
+ {
+ MetaPolyLineAction* pPolyLineAction = dynamic_cast< MetaPolyLineAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolyLineAction)
+ {
+ // replace MetaPolyLineAction when we have a single polygon. Do not rely on the
+ // same point count; the originally written GDI_POLYLINE_ACTION may have been
+ // Subdivided for better quality for older usages
+ if(1 == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolyLineAction(
+ aInputPolyPolygon.GetObject(0),
+ pPolyLineAction->GetLineInfo()),
+ nLastPolygonAction);
+ }
+ }
+ else
+ {
+ MetaPolyPolygonAction* pPolyPolygonAction = dynamic_cast< MetaPolyPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolyPolygonAction)
+ {
+ // replace MetaPolyPolygonAction when we have a curved polygon. Do rely on the
+ // same sub-polygon count
+ if(pPolyPolygonAction->GetPolyPolygon().Count() == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolyPolygonAction(
+ aInputPolyPolygon),
+ nLastPolygonAction);
+ }
+ }
+ else
+ {
+ MetaPolygonAction* pPolygonAction = dynamic_cast< MetaPolygonAction* >(rMtf.GetAction(nLastPolygonAction));
+
+ if(pPolygonAction)
+ {
+ // replace MetaPolygonAction
+ if(1 == aInputPolyPolygon.Count())
+ {
+ rMtf.ReplaceAction(
+ new MetaPolygonAction(
+ aInputPolyPolygon.GetObject(0)),
+ nLastPolygonAction);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case GDI_RECT_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+ sal_Int32 nTmp(0), nTmp1(0);
+ rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
+
+ if( nTmp || nTmp1 )
+ rMtf.AddAction( new MetaRoundRectAction( aRect, nTmp, nTmp1 ) );
+ else
+ {
+ rMtf.AddAction( new MetaRectAction( aRect ) );
+
+ if( bFatLine )
+ rMtf.AddAction( new MetaPolyLineAction( aRect, aLineInfo ) );
+ }
+ }
+ break;
+
+ case GDI_ELLIPSE_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+
+ if( bFatLine )
+ {
+ const tools::Polygon aPoly( aRect.Center(), aRect.GetWidth() >> 1, aRect.GetHeight() >> 1 );
+
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaEllipseAction( aRect ) );
+ }
+ break;
+
+ case GDI_ARC_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+ aSerializer.readPoint(aPt);
+ aSerializer.readPoint(aPt1);
+
+ if( bFatLine )
+ {
+ const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Arc );
+
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaArcAction( aRect, aPt, aPt1 ) );
+ }
+ break;
+
+ case GDI_PIE_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+ aSerializer.readPoint(aPt);
+ aSerializer.readPoint(aPt1);
+
+ if( bFatLine )
+ {
+ const tools::Polygon aPoly( aRect, aPt, aPt1, PolyStyle::Pie );
+
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
+ rMtf.AddAction( new MetaPolygonAction( aPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aPoly, aLineInfo ) );
+ }
+ else
+ rMtf.AddAction( new MetaPieAction( aRect, aPt, aPt1 ) );
+ }
+ break;
+
+ case GDI_INVERTRECT_ACTION:
+ case GDI_HIGHLIGHTRECT_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::RASTEROP ) );
+ rMtf.AddAction( new MetaRasterOpAction( RasterOp::Invert ) );
+ rMtf.AddAction( new MetaRectAction( aRect ) );
+ rMtf.AddAction( new MetaPopAction() );
+ }
+ break;
+
+ case GDI_POLYLINE_ACTION:
+ {
+ if (ImplReadPoly(rIStm, aActionPoly))
+ {
+ nLastPolygonAction = rMtf.GetActionSize();
+
+ if( bFatLine )
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
+ else
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly ) );
+ }
+ }
+ break;
+
+ case GDI_POLYGON_ACTION:
+ {
+ if (ImplReadPoly(rIStm, aActionPoly))
+ {
+ if( bFatLine )
+ {
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
+ rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+ rMtf.AddAction( new MetaPolyLineAction( aActionPoly, aLineInfo ) );
+ }
+ else
+ {
+ nLastPolygonAction = rMtf.GetActionSize();
+ rMtf.AddAction( new MetaPolygonAction( aActionPoly ) );
+ }
+ }
+ }
+ break;
+
+ case GDI_POLYPOLYGON_ACTION:
+ {
+ tools::PolyPolygon aPolyPoly;
+
+ if (ImplReadPolyPoly(rIStm, aPolyPoly))
+ {
+ if( bFatLine )
+ {
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::LINECOLOR ) );
+ rMtf.AddAction( new MetaLineColorAction( COL_TRANSPARENT, false ) );
+ rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
+ rMtf.AddAction( new MetaPopAction() );
+
+ for( sal_uInt16 nPoly = 0, nCount = aPolyPoly.Count(); nPoly < nCount; nPoly++ )
+ rMtf.AddAction( new MetaPolyLineAction( aPolyPoly[ nPoly ], aLineInfo ) );
+ }
+ else
+ {
+ nLastPolygonAction = rMtf.GetActionSize();
+ rMtf.AddAction( new MetaPolyPolygonAction( aPolyPoly ) );
+ }
+ }
+ }
+ break;
+
+ case GDI_FONT_ACTION:
+ {
+ vcl::Font aFont;
+ char aName[LF_FACESIZE+1];
+
+ ImplReadColor( rIStm, aActionColor ); aFont.SetColor( aActionColor );
+ ImplReadColor( rIStm, aActionColor ); aFont.SetFillColor( aActionColor );
+ size_t nRet = rIStm.ReadBytes(aName, LF_FACESIZE);
+ aName[nRet] = 0;
+ aFont.SetFamilyName( OUString( aName, strlen(aName), rIStm.GetStreamCharSet() ) );
+
+ sal_Int32 nWidth(0), nHeight(0);
+ rIStm.ReadInt32(nWidth).ReadInt32(nHeight);
+ sal_Int16 nCharOrient(0), nLineOrient(0);
+ rIStm.ReadInt16(nCharOrient).ReadInt16(nLineOrient);
+ sal_Int16 nCharSet(0), nFamily(0), nPitch(0), nAlign(0), nWeight(0), nUnderline(0), nStrikeout(0);
+ rIStm.ReadInt16(nCharSet).ReadInt16(nFamily).ReadInt16(nPitch).ReadInt16(nAlign).ReadInt16(nWeight).ReadInt16(nUnderline).ReadInt16(nStrikeout);
+ bool bItalic(false), bOutline(false), bShadow(false), bTransparent(false);
+ rIStm.ReadCharAsBool(bItalic).ReadCharAsBool(bOutline).ReadCharAsBool(bShadow).ReadCharAsBool(bTransparent);
+
+ aFont.SetFontSize( Size( nWidth, nHeight ) );
+ aFont.SetCharSet( static_cast<rtl_TextEncoding>(nCharSet) );
+ aFont.SetFamily( static_cast<FontFamily>(nFamily & SAL_MAX_ENUM) );
+ aFont.SetPitch( static_cast<FontPitch>(nPitch & SAL_MAX_ENUM) );
+ aFont.SetAlignment( static_cast<TextAlign>(nAlign & SAL_MAX_ENUM) );
+ aFont.SetWeight( ( nWeight == 1 ) ? WEIGHT_LIGHT : ( nWeight == 2 ) ? WEIGHT_NORMAL :
+ ( nWeight == 3 ) ? WEIGHT_BOLD : WEIGHT_DONTKNOW );
+ aFont.SetUnderline( static_cast<FontLineStyle>(nUnderline & SAL_MAX_ENUM) );
+ aFont.SetStrikeout( static_cast<FontStrikeout>(nStrikeout & SAL_MAX_ENUM) );
+ aFont.SetItalic( bItalic ? ITALIC_NORMAL : ITALIC_NONE );
+ aFont.SetOutline( bOutline );
+ aFont.SetShadow( bShadow );
+ aFont.SetOrientation( Degree10(nLineOrient) );
+ aFont.SetTransparent( bTransparent );
+
+ eActualCharSet = aFont.GetCharSet();
+ if ( eActualCharSet == RTL_TEXTENCODING_DONTKNOW )
+ eActualCharSet = osl_getThreadTextEncoding();
+
+ rMtf.AddAction( new MetaFontAction( aFont ) );
+ rMtf.AddAction( new MetaTextAlignAction( aFont.GetAlignment() ) );
+ rMtf.AddAction( new MetaTextColorAction( aFont.GetColor() ) );
+ rMtf.AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev->SetFont( aFont );
+ }
+ break;
+
+ case GDI_TEXT_ACTION:
+ {
+ sal_Int32 nIndex(0), nLen(0), nTmp(0);
+ aSerializer.readPoint(aPt);
+ rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp );
+ if (nTmp > 0)
+ {
+ OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
+ sal_uInt8 nTerminator = 0;
+ rIStm.ReadUChar( nTerminator );
+ SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
+
+ OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ ClampRange(aStr, nIndex, nLen);
+ rMtf.AddAction( new MetaTextAction( aPt, aStr, nIndex, nLen ) );
+ }
+
+ if (nActionSize < 24)
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ else
+ rIStm.Seek(nActBegin + nActionSize);
+ }
+ break;
+
+ case GDI_TEXTARRAY_ACTION:
+ {
+ sal_Int32 nIndex(0), nLen(0), nAryLen(0), nTmp(0);
+ aSerializer.readPoint(aPt);
+ rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nAryLen );
+ if (nTmp > 0)
+ {
+ OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
+ sal_uInt8 nTerminator = 0;
+ rIStm.ReadUChar( nTerminator );
+ SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
+
+ OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
+
+ std::vector<sal_Int32> aDXAry;
+ if (nAryLen > 0)
+ {
+ const size_t nMinRecordSize = sizeof(sal_Int32);
+ const size_t nMaxRecords = rIStm.remainingSize() / nMinRecordSize;
+ if (o3tl::make_unsigned(nAryLen) > nMaxRecords)
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords <<
+ " max possible entries, but " << nAryLen << " claimed, truncating");
+ nAryLen = nMaxRecords;
+ }
+
+ sal_Int32 nStrLen( aStr.getLength() );
+
+ sal_Int32 nDXAryLen = std::max(nAryLen, nStrLen);
+
+ if (nDXAryLen < nLen)
+ {
+ //MetaTextArrayAction ctor expects pDXAry to be >= nLen if set, so if this can't
+ //be achieved, don't read it, it's utterly broken.
+ SAL_WARN("vcl.gdi", "dxary too short, discarding completely");
+ rIStm.SeekRel(sizeof(sal_Int32) * nDXAryLen);
+ nLen = 0;
+ nIndex = 0;
+ }
+ else
+ {
+ aDXAry.resize(nDXAryLen);
+
+ for (sal_Int32 j = 0; j < nAryLen; ++j)
+ {
+ rIStm.ReadInt32( nTmp );
+ aDXAry[ j ] = nTmp;
+ }
+
+ // #106172# Add last DX array elem, if missing
+ if( nAryLen != nStrLen )
+ {
+ if (nAryLen+1 == nStrLen && nIndex >= 0)
+ {
+ std::vector<sal_Int32> aTmpAry;
+
+ aFontVDev->GetTextArray( aStr, &aTmpAry, nIndex, nLen );
+
+ if (aTmpAry.size() < o3tl::make_unsigned(nStrLen))
+ SAL_WARN("vcl.gdi", "TextArray too short to recover missing element");
+ else
+ {
+ // now, the difference between the
+ // last and the second last DX array
+ // is the advancement for the last
+ // glyph. Thus, to complete our meta
+ // action's DX array, just add that
+ // difference to last elem and store
+ // in very last.
+ if( nStrLen > 1 )
+ aDXAry[ nStrLen-1 ] = aDXAry[ nStrLen-2 ] + aTmpAry[ nStrLen-1 ] - aTmpAry[ nStrLen-2 ];
+ else
+ aDXAry[ nStrLen-1 ] = aTmpAry[ nStrLen-1 ]; // len=1: 0th position taken to be 0
+ }
+ }
+#ifdef DBG_UTIL
+ else
+ OSL_FAIL("More than one DX array element missing on SVM import");
+#endif
+ }
+ }
+ }
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ ClampRange(aStr, nIndex, nLen, &aDXAry);
+ rMtf.AddAction( new MetaTextArrayAction( aPt, aStr, aDXAry, nIndex, nLen ) );
+ }
+
+ if (nActionSize < 24)
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ else
+ rIStm.Seek(nActBegin + nActionSize);
+ }
+ break;
+
+ case GDI_STRETCHTEXT_ACTION:
+ {
+ sal_Int32 nIndex(0), nLen(0), nWidth(0), nTmp(0);
+
+ aSerializer.readPoint(aPt);
+ rIStm.ReadInt32( nIndex ).ReadInt32( nLen ).ReadInt32( nTmp ).ReadInt32( nWidth );
+ if (nTmp > 0)
+ {
+ OString aByteStr = read_uInt8s_ToOString(rIStm, nTmp);
+ sal_uInt8 nTerminator = 0;
+ rIStm.ReadUChar( nTerminator );
+ SAL_WARN_IF( nTerminator != 0, "vcl.gdi", "expected string to be NULL terminated" );
+
+ OUString aStr(OStringToOUString(aByteStr, eActualCharSet));
+ if ( nUnicodeCommentActionNumber == i )
+ ImplReadUnicodeComment( nUnicodeCommentStreamPos, rIStm, aStr );
+ ClampRange(aStr, nIndex, nLen);
+ rMtf.AddAction( new MetaStretchTextAction( aPt, nWidth, aStr, nIndex, nLen ) );
+ }
+
+ if (nActionSize < 28)
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ else
+ rIStm.Seek(nActBegin + nActionSize);
+ }
+ break;
+
+ case GDI_BITMAP_ACTION:
+ {
+ Bitmap aBmp;
+
+ aSerializer.readPoint(aPt);
+ ReadDIB(aBmp, rIStm, true);
+ rMtf.AddAction( new MetaBmpAction( aPt, aBmp ) );
+ }
+ break;
+
+ case GDI_BITMAPSCALE_ACTION:
+ {
+ Bitmap aBmp;
+
+ aSerializer.readPoint(aPt);
+ aSerializer.readSize(aSz);
+ ReadDIB(aBmp, rIStm, true);
+ rMtf.AddAction( new MetaBmpScaleAction( aPt, aSz, aBmp ) );
+ }
+ break;
+
+ case GDI_BITMAPSCALEPART_ACTION:
+ {
+ Bitmap aBmp;
+ Size aSz2;
+
+ aSerializer.readPoint(aPt);
+ aSerializer.readSize(aSz);
+ aSerializer.readPoint(aPt1);
+ aSerializer.readSize(aSz2);
+ ReadDIB(aBmp, rIStm, true);
+ rMtf.AddAction( new MetaBmpScalePartAction( aPt, aSz, aPt1, aSz2, aBmp ) );
+ }
+ break;
+
+ case GDI_PEN_ACTION:
+ {
+ ImplReadColor( rIStm, aActionColor );
+
+ sal_Int32 nPenWidth(0);
+ sal_Int16 nPenStyle(0);
+ rIStm.ReadInt32( nPenWidth ).ReadInt16( nPenStyle );
+
+ aLineInfo.SetStyle( nPenStyle ? LineStyle::Solid : LineStyle::NONE );
+ aLineInfo.SetWidth( nPenWidth );
+ bFatLine = nPenStyle && !aLineInfo.IsDefault();
+
+ rMtf.AddAction( new MetaLineColorAction( aActionColor, nPenStyle != 0 ) );
+ }
+ break;
+
+ case GDI_FILLBRUSH_ACTION:
+ {
+ ImplReadColor( rIStm, aActionColor );
+ rIStm.SeekRel( 6 );
+ sal_Int16 nBrushStyle(0);
+ rIStm.ReadInt16( nBrushStyle );
+ rMtf.AddAction( new MetaFillColorAction( aActionColor, nBrushStyle != 0 ) );
+ rIStm.SeekRel( 2 );
+ }
+ break;
+
+ case GDI_MAPMODE_ACTION:
+ {
+ if (ImplReadMapMode(rIStm, aMapMode))
+ {
+ rMtf.AddAction(new MetaMapModeAction(aMapMode));
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev->SetMapMode(aMapMode);
+ };
+ }
+ break;
+
+ case GDI_CLIPREGION_ACTION:
+ {
+ vcl::Region aRegion;
+ bool bClip = false;
+
+ sal_Int16 nRegType(0);
+ sal_Int16 bIntersect(0);
+ rIStm.ReadInt16( nRegType ).ReadInt16( bIntersect );
+ ImplReadRect( rIStm, aRect );
+
+ switch( nRegType )
+ {
+ case 0:
+ break;
+
+ case 1:
+ {
+ tools::Rectangle aRegRect;
+
+ ImplReadRect( rIStm, aRegRect );
+ aRegion = vcl::Region( aRegRect );
+ bClip = true;
+ }
+ break;
+
+ case 2:
+ {
+ if (ImplReadPoly(rIStm, aActionPoly))
+ {
+ aRegion = vcl::Region( aActionPoly );
+ bClip = true;
+ }
+ }
+ break;
+
+ case 3:
+ {
+ bool bSuccess = true;
+ tools::PolyPolygon aPolyPoly;
+ sal_Int32 nPolyCount32(0);
+ rIStm.ReadInt32(nPolyCount32);
+ sal_uInt16 nPolyCount(nPolyCount32);
+
+ for (sal_uInt16 j = 0; j < nPolyCount && rIStm.good(); ++j)
+ {
+ if (!ImplReadPoly(rIStm, aActionPoly))
+ {
+ bSuccess = false;
+ break;
+ }
+ aPolyPoly.Insert(aActionPoly);
+ }
+
+ if (bSuccess)
+ {
+ aRegion = vcl::Region( aPolyPoly );
+ bClip = true;
+ }
+ }
+ break;
+ }
+
+ if( bIntersect )
+ aRegion.Intersect( aRect );
+
+ rMtf.AddAction( new MetaClipRegionAction( aRegion, bClip ) );
+ }
+ break;
+
+ case GDI_MOVECLIPREGION_ACTION:
+ {
+ sal_Int32 nTmp(0), nTmp1(0);
+ rIStm.ReadInt32( nTmp ).ReadInt32( nTmp1 );
+ rMtf.AddAction( new MetaMoveClipRegionAction( nTmp, nTmp1 ) );
+ }
+ break;
+
+ case GDI_ISECTCLIPREGION_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+ rMtf.AddAction( new MetaISectRectClipRegionAction( aRect ) );
+ }
+ break;
+
+ case GDI_RASTEROP_ACTION:
+ {
+ RasterOp eRasterOp;
+
+ sal_Int16 nRasterOp(0);
+ rIStm.ReadInt16( nRasterOp );
+
+ switch( nRasterOp )
+ {
+ case 1:
+ eRasterOp = RasterOp::Invert;
+ break;
+
+ case 4:
+ case 5:
+ eRasterOp = RasterOp::Xor;
+ break;
+
+ default:
+ eRasterOp = RasterOp::OverPaint;
+ break;
+ }
+
+ rMtf.AddAction( new MetaRasterOpAction( eRasterOp ) );
+ }
+ break;
+
+ case GDI_PUSH_ACTION:
+ {
+ aLIStack.push(aLineInfo);
+ rMtf.AddAction( new MetaPushAction( vcl::PushFlags::ALL ) );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev->Push();
+ }
+ break;
+
+ case GDI_POP_ACTION:
+ {
+
+ std::optional<LineInfo> xLineInfo;
+ if (!aLIStack.empty())
+ {
+ xLineInfo = std::move(aLIStack.top());
+ aLIStack.pop();
+ }
+
+ // restore line info
+ if (xLineInfo)
+ {
+ aLineInfo = *xLineInfo;
+ xLineInfo.reset();
+ bFatLine = ( LineStyle::NONE != aLineInfo.GetStyle() ) && !aLineInfo.IsDefault();
+ }
+
+ rMtf.AddAction( new MetaPopAction() );
+
+ // #106172# Track font relevant data in shadow VDev
+ aFontVDev->Pop();
+ }
+ break;
+
+ case GDI_GRADIENT_ACTION:
+ {
+ ImplReadRect( rIStm, aRect );
+
+ sal_Int16 nStyle(0);
+ rIStm.ReadInt16( nStyle );
+
+ Color aStartCol, aEndCol;
+ ImplReadColor( rIStm, aStartCol );
+ ImplReadColor( rIStm, aEndCol );
+
+ sal_Int16 nAngle(0), nBorder(0), nOfsX(0), nOfsY(0), nIntensityStart(0), nIntensityEnd(0);
+ rIStm.ReadInt16( nAngle ).ReadInt16( nBorder ).ReadInt16( nOfsX ).ReadInt16( nOfsY ).ReadInt16( nIntensityStart ).ReadInt16( nIntensityEnd );
+
+ Gradient aGrad( static_cast<GradientStyle>(nStyle), aStartCol, aEndCol );
+
+ aGrad.SetAngle( Degree10(nAngle) );
+ aGrad.SetBorder( nBorder );
+ aGrad.SetOfsX( nOfsX );
+ aGrad.SetOfsY( nOfsY );
+ aGrad.SetStartIntensity( nIntensityStart );
+ aGrad.SetEndIntensity( nIntensityEnd );
+ rMtf.AddAction( new MetaGradientAction( aRect, aGrad ) );
+ }
+ break;
+
+ case GDI_TRANSPARENT_COMMENT:
+ {
+ tools::PolyPolygon aPolyPoly;
+ sal_Int32 nFollowingActionCount(0);
+ sal_Int16 nTrans(0);
+
+ ReadPolyPolygon( rIStm, aPolyPoly );
+ rIStm.ReadInt16( nTrans ).ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaTransparentAction( aPolyPoly, nTrans ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_FLOATTRANSPARENT_COMMENT:
+ {
+ GDIMetaFile aMtf;
+ Point aPos;
+ Size aSize;
+ Gradient aGradient;
+ sal_Int32 nFollowingActionCount(0);
+
+ SvmReader aReader( rIStm );
+ aReader.Read( aMtf );
+ aSerializer.readPoint(aPos);
+ aSerializer.readSize(aSize);
+ aSerializer.readGradient(aGradient);
+ rIStm.ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaFloatTransparentAction( aMtf, aPos, aSize, aGradient ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_HATCH_COMMENT:
+ {
+ tools::PolyPolygon aPolyPoly;
+ Hatch aHatch;
+ sal_Int32 nFollowingActionCount(0);
+
+ ReadPolyPolygon( rIStm, aPolyPoly );
+ ReadHatch( rIStm, aHatch );
+ rIStm.ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaHatchAction( aPolyPoly, aHatch ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_REFPOINT_COMMENT:
+ {
+ Point aRefPoint;
+ bool bSet(false);
+ sal_Int32 nFollowingActionCount(0);
+
+ aSerializer.readPoint(aRefPoint);
+ rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaRefPointAction( aRefPoint, bSet ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+
+ // #106172# Track font relevant data in shadow VDev
+ if( bSet )
+ aFontVDev->SetRefPoint( aRefPoint );
+ else
+ aFontVDev->SetRefPoint();
+ }
+ break;
+
+ case GDI_TEXTLINECOLOR_COMMENT:
+ {
+ Color aColor;
+ bool bSet(false);
+ sal_Int32 nFollowingActionCount(0);
+
+ aSerializer.readColor(aColor);
+ rIStm.ReadCharAsBool( bSet ).ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaTextLineColorAction( aColor, bSet ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_TEXTLINE_COMMENT:
+ {
+ Point aStartPt;
+ sal_Int32 nWidth(0);
+ sal_uInt32 nStrikeout(0);
+ sal_uInt32 nUnderline(0);
+ sal_Int32 nFollowingActionCount(0);
+
+ aSerializer.readPoint(aStartPt);
+ rIStm.ReadInt32(nWidth ).ReadUInt32(nStrikeout).ReadUInt32(nUnderline).ReadInt32(nFollowingActionCount);
+ ImplSkipActions(rIStm, nFollowingActionCount);
+ rMtf.AddAction( new MetaTextLineAction( aStartPt, nWidth,
+ static_cast<FontStrikeout>(nStrikeout & SAL_MAX_ENUM),
+ static_cast<FontLineStyle>(nUnderline & SAL_MAX_ENUM),
+ LINESTYLE_NONE ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_GRADIENTEX_COMMENT:
+ {
+ tools::PolyPolygon aPolyPoly;
+ Gradient aGradient;
+ sal_Int32 nFollowingActionCount(0);
+
+ ReadPolyPolygon( rIStm, aPolyPoly );
+ aSerializer.readGradient(aGradient);
+ rIStm.ReadInt32( nFollowingActionCount );
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction( new MetaGradientExAction( aPolyPoly, aGradient ) );
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_COMMENT_COMMENT:
+ {
+ std::vector<sal_uInt8> aData;
+
+ OString aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm);
+ sal_Int32 nValue(0);
+ sal_uInt32 nDataSize(0);
+ rIStm.ReadInt32(nValue).ReadUInt32(nDataSize);
+
+ if (nDataSize)
+ {
+ const size_t nMaxPossibleData = rIStm.remainingSize();
+ if (nDataSize > nMaxPossibleActions)
+ {
+ SAL_WARN("vcl.gdi", "svm record claims to have: " << nDataSize << " data, but only " << nMaxPossibleData << " possible");
+ nDataSize = nMaxPossibleActions;
+ }
+ aData.resize(nDataSize);
+ nDataSize = rIStm.ReadBytes(aData.data(), nDataSize);
+ }
+
+ sal_Int32 nFollowingActionCount(0);
+ rIStm.ReadInt32(nFollowingActionCount);
+ ImplSkipActions( rIStm, nFollowingActionCount );
+ rMtf.AddAction(new MetaCommentAction(aComment, nValue, aData.data(), nDataSize));
+
+ i = SkipActions(i, nFollowingActionCount, nActions);
+ }
+ break;
+
+ case GDI_UNICODE_COMMENT:
+ {
+ nUnicodeCommentActionNumber = i + 1;
+ nUnicodeCommentStreamPos = rIStm.Tell() - 6;
+ if (nActionSize < 4)
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ else
+ rIStm.SeekRel(nActionSize - 4);
+ }
+ break;
+
+ default:
+ if (nActionSize < 4)
+ rIStm.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ else
+ rIStm.SeekRel(nActionSize - 4);
+ break;
+ }
+ }
+
+ rIStm.SetEndian( nOldFormat );
+}
+
+bool TestImportSVM(SvStream& rStream)
+{
+ GDIMetaFile aGDIMetaFile;
+ SvmReader aReader(rStream);
+ aReader.Read(aGDIMetaFile);
+ ScopedVclPtrInstance<VirtualDevice> aVDev;
+ aVDev->SetTextRenderModeForResolutionIndependentLayout(true);
+ try
+ {
+ aGDIMetaFile.Play(*aVDev);
+ }
+ catch (const boost::bad_rational&)
+ {
+ return false;
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/svm/SvmConverter.hxx b/vcl/source/filter/svm/SvmConverter.hxx
new file mode 100644
index 000000000..23185dc04
--- /dev/null
+++ b/vcl/source/filter/svm/SvmConverter.hxx
@@ -0,0 +1,92 @@
+/* -*- 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_INC_SVMCONVERTER_HXX
+#define INCLUDED_VCL_INC_SVMCONVERTER_HXX
+
+#include <vcl/dllapi.h>
+#include <vcl/gdimtf.hxx>
+
+#define GDI_PIXEL_ACTION 1
+#define GDI_POINT_ACTION 2
+#define GDI_LINE_ACTION 3
+#define GDI_RECT_ACTION 4
+#define GDI_ELLIPSE_ACTION 5
+#define GDI_ARC_ACTION 6
+#define GDI_PIE_ACTION 7
+#define GDI_INVERTRECT_ACTION 8
+#define GDI_HIGHLIGHTRECT_ACTION 9
+#define GDI_POLYLINE_ACTION 10
+#define GDI_POLYGON_ACTION 11
+#define GDI_POLYPOLYGON_ACTION 12
+#define GDI_TEXT_ACTION 13
+#define GDI_TEXTARRAY_ACTION 14
+#define GDI_STRETCHTEXT_ACTION 15
+#define GDI_BITMAP_ACTION 17
+#define GDI_BITMAPSCALE_ACTION 18
+#define GDI_PEN_ACTION 19
+#define GDI_FONT_ACTION 20
+#define GDI_FILLBRUSH_ACTION 22
+#define GDI_MAPMODE_ACTION 23
+#define GDI_CLIPREGION_ACTION 24
+#define GDI_RASTEROP_ACTION 25
+#define GDI_PUSH_ACTION 26
+#define GDI_POP_ACTION 27
+#define GDI_MOVECLIPREGION_ACTION 28
+#define GDI_ISECTCLIPREGION_ACTION 29
+#define GDI_BITMAPSCALEPART_ACTION 32
+#define GDI_GRADIENT_ACTION 33
+
+#define GDI_TRANSPARENT_COMMENT 1024
+#define GDI_HATCH_COMMENT 1025
+#define GDI_REFPOINT_COMMENT 1026
+#define GDI_TEXTLINECOLOR_COMMENT 1027
+#define GDI_TEXTLINE_COMMENT 1028
+#define GDI_FLOATTRANSPARENT_COMMENT 1029
+#define GDI_GRADIENTEX_COMMENT 1030
+#define GDI_COMMENT_COMMENT 1031
+#define GDI_UNICODE_COMMENT 1032
+
+#define GDI_LINEJOIN_ACTION 1033
+#define GDI_EXTENDEDPOLYGON_ACTION 1034
+#define GDI_LINEDASHDOT_ACTION 1035
+
+#define GDI_LINECAP_ACTION 1036
+
+/**
+ * Converts old SVGDI aka SVM1 format data to current VCLMTF aka SVM2 format metafile data.
+ */
+class SVMConverter
+{
+private:
+ static void ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf );
+
+public:
+ SVMConverter( SvStream& rIStm, GDIMetaFile& rMtf );
+
+private:
+ SVMConverter( const SVMConverter& ) = delete;
+ SVMConverter& operator=( const SVMConverter& ) = delete;
+};
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSVM(SvStream& rStream);
+
+#endif // INCLUDED_VCL_INC_SVMCONVERTER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/svm/SvmReader.cxx b/vcl/source/filter/svm/SvmReader.cxx
new file mode 100644
index 000000000..f02451ea3
--- /dev/null
+++ b/vcl/source/filter/svm/SvmReader.cxx
@@ -0,0 +1,1438 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/log.hxx>
+#include <osl/thread.h>
+#include <tools/stream.hxx>
+#include <tools/vcompat.hxx>
+
+#include <vcl/filter/SvmReader.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <vcl/dibtools.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+
+#include "SvmConverter.hxx"
+
+namespace
+{
+class DepthGuard
+{
+private:
+ ImplMetaReadData& m_rData;
+ rtl_TextEncoding m_eOrigCharSet;
+
+public:
+ DepthGuard(ImplMetaReadData& rData, SvStream const& rIStm)
+ : m_rData(rData)
+ , m_eOrigCharSet(m_rData.meActualCharSet)
+ {
+ ++m_rData.mnParseDepth;
+ m_rData.meActualCharSet = rIStm.GetStreamCharSet();
+ }
+ bool TooDeep() const { return m_rData.mnParseDepth > 1024; }
+ ~DepthGuard()
+ {
+ --m_rData.mnParseDepth;
+ m_rData.meActualCharSet = m_eOrigCharSet;
+ }
+};
+}
+
+SvmReader::SvmReader(SvStream& rIStm)
+ : mrStream(rIStm)
+{
+}
+
+SvStream& SvmReader::Read(GDIMetaFile& rMetaFile, ImplMetaReadData* pData)
+{
+ if (mrStream.GetError())
+ {
+ SAL_WARN("vcl.gdi", "Stream error: " << mrStream.GetError());
+ return mrStream;
+ }
+
+ sal_uInt64 nStmPos = mrStream.Tell();
+ SvStreamEndian nOldFormat = mrStream.GetEndian();
+
+ mrStream.SetEndian(SvStreamEndian::LITTLE);
+
+ try
+ {
+ char aId[7];
+ aId[0] = 0;
+ aId[6] = 0;
+ mrStream.ReadBytes(aId, 6);
+ if (mrStream.good() && !strcmp(aId, "VCLMTF"))
+ {
+ // new format
+ sal_uInt32 nStmCompressMode = 0;
+ sal_uInt32 nCount = 0;
+ std::unique_ptr<VersionCompatRead> pCompat(new VersionCompatRead(mrStream));
+
+ mrStream.ReadUInt32(nStmCompressMode);
+ TypeSerializer aSerializer(mrStream);
+ MapMode aMapMode;
+ aSerializer.readMapMode(aMapMode);
+ rMetaFile.SetPrefMapMode(aMapMode);
+ Size aSize;
+ aSerializer.readSize(aSize);
+ rMetaFile.SetPrefSize(aSize);
+ mrStream.ReadUInt32(nCount);
+
+ pCompat.reset(); // destructor writes stuff into the header
+
+ std::unique_ptr<ImplMetaReadData> xReadData;
+ if (!pData)
+ {
+ xReadData.reset(new ImplMetaReadData);
+ pData = xReadData.get();
+ }
+ DepthGuard aDepthGuard(*pData, mrStream);
+
+ if (aDepthGuard.TooDeep())
+ throw std::runtime_error("too much recursion");
+
+ for (sal_uInt32 nAction = 0; (nAction < nCount) && !mrStream.eof(); nAction++)
+ {
+ rtl::Reference<MetaAction> pAction = MetaActionHandler(pData);
+ if (pAction)
+ {
+ if (pAction->GetType() == MetaActionType::COMMENT)
+ {
+ MetaCommentAction* pCommentAct
+ = static_cast<MetaCommentAction*>(pAction.get());
+
+ if (pCommentAct->GetComment() == "EMF_PLUS")
+ rMetaFile.UseCanvas(true);
+ }
+ rMetaFile.AddAction(pAction);
+ }
+ }
+ }
+ else
+ {
+ mrStream.Seek(nStmPos);
+ SVMConverter(mrStream, rMetaFile);
+ }
+ }
+ catch (...)
+ {
+ SAL_WARN("vcl", "GDIMetaFile exception during load");
+ mrStream.SetError(SVSTREAM_FILEFORMAT_ERROR);
+ };
+
+ // check for errors
+ if (mrStream.GetError())
+ {
+ rMetaFile.Clear();
+ mrStream.Seek(nStmPos);
+ }
+
+ mrStream.SetEndian(nOldFormat);
+ return mrStream;
+}
+
+rtl::Reference<MetaAction> SvmReader::MetaActionHandler(ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaAction> pAction;
+ sal_uInt16 nTmp = 0;
+ mrStream.ReadUInt16(nTmp);
+ MetaActionType nType = static_cast<MetaActionType>(nTmp);
+
+ switch (nType)
+ {
+ case MetaActionType::NONE:
+ return DefaultHandler();
+ case MetaActionType::PIXEL:
+ return PixelHandler();
+ case MetaActionType::POINT:
+ return PointHandler();
+ case MetaActionType::LINE:
+ return LineHandler();
+ case MetaActionType::RECT:
+ return RectHandler();
+ case MetaActionType::ROUNDRECT:
+ return RoundRectHandler();
+ case MetaActionType::ELLIPSE:
+ return EllipseHandler();
+ case MetaActionType::ARC:
+ return ArcHandler();
+ case MetaActionType::PIE:
+ return PieHandler();
+ case MetaActionType::CHORD:
+ return ChordHandler();
+ case MetaActionType::POLYLINE:
+ return PolyLineHandler();
+ case MetaActionType::POLYGON:
+ return PolygonHandler();
+ case MetaActionType::POLYPOLYGON:
+ return PolyPolygonHandler();
+ case MetaActionType::TEXT:
+ return TextHandler(pData);
+ case MetaActionType::TEXTARRAY:
+ return TextArrayHandler(pData);
+ case MetaActionType::STRETCHTEXT:
+ return StretchTextHandler(pData);
+ case MetaActionType::TEXTRECT:
+ return TextRectHandler(pData);
+ case MetaActionType::TEXTLINE:
+ return TextLineHandler();
+ case MetaActionType::BMP:
+ return BmpHandler();
+ case MetaActionType::BMPSCALE:
+ return BmpScaleHandler();
+ case MetaActionType::BMPSCALEPART:
+ return BmpScalePartHandler();
+ case MetaActionType::BMPEX:
+ return BmpExHandler();
+ case MetaActionType::BMPEXSCALE:
+ return BmpExScaleHandler();
+ case MetaActionType::BMPEXSCALEPART:
+ return BmpExScalePartHandler();
+ case MetaActionType::MASK:
+ return MaskHandler();
+ case MetaActionType::MASKSCALE:
+ return MaskScaleHandler();
+ case MetaActionType::MASKSCALEPART:
+ return MaskScalePartHandler();
+ case MetaActionType::GRADIENT:
+ return GradientHandler();
+ case MetaActionType::GRADIENTEX:
+ return GradientExHandler();
+ case MetaActionType::HATCH:
+ return HatchHandler();
+ case MetaActionType::WALLPAPER:
+ return WallpaperHandler();
+ case MetaActionType::CLIPREGION:
+ return ClipRegionHandler();
+ case MetaActionType::ISECTRECTCLIPREGION:
+ return ISectRectClipRegionHandler();
+ case MetaActionType::ISECTREGIONCLIPREGION:
+ return ISectRegionClipRegionHandler();
+ case MetaActionType::MOVECLIPREGION:
+ return MoveClipRegionHandler();
+ case MetaActionType::LINECOLOR:
+ return LineColorHandler();
+ case MetaActionType::FILLCOLOR:
+ return FillColorHandler();
+ case MetaActionType::TEXTCOLOR:
+ return TextColorHandler();
+ case MetaActionType::TEXTFILLCOLOR:
+ return TextFillColorHandler();
+ case MetaActionType::TEXTLINECOLOR:
+ return TextLineColorHandler();
+ case MetaActionType::OVERLINECOLOR:
+ return OverlineColorHandler();
+ case MetaActionType::TEXTALIGN:
+ return TextAlignHandler();
+ case MetaActionType::MAPMODE:
+ return MapModeHandler();
+ case MetaActionType::FONT:
+ return FontHandler(pData);
+ case MetaActionType::PUSH:
+ return PushHandler();
+ case MetaActionType::POP:
+ return PopHandler();
+ case MetaActionType::RASTEROP:
+ return RasterOpHandler();
+ case MetaActionType::Transparent:
+ return TransparentHandler();
+ case MetaActionType::FLOATTRANSPARENT:
+ return FloatTransparentHandler(pData);
+ case MetaActionType::EPS:
+ return EPSHandler();
+ case MetaActionType::REFPOINT:
+ return RefPointHandler();
+ case MetaActionType::COMMENT:
+ return CommentHandler();
+ case MetaActionType::LAYOUTMODE:
+ return LayoutModeHandler();
+ case MetaActionType::TEXTLANGUAGE:
+ return TextLanguageHandler();
+
+ default:
+ {
+ VersionCompatRead aCompat(mrStream);
+ }
+ break;
+ }
+
+ return pAction;
+}
+
+void SvmReader::ReadColor(Color& rColor)
+{
+ sal_uInt32 nTmp(0);
+ mrStream.ReadUInt32(nTmp);
+ rColor = ::Color(ColorTransparency, nTmp);
+}
+
+rtl::Reference<MetaAction> SvmReader::LineColorHandler()
+{
+ rtl::Reference<MetaLineColorAction> pAction(new MetaLineColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Color aColor;
+ ReadColor(aColor);
+ bool aBool(false);
+ mrStream.ReadCharAsBool(aBool);
+
+ pAction->SetSetting(aBool);
+ pAction->SetColor(aColor);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::FillColorHandler()
+{
+ rtl::Reference<MetaFillColorAction> pAction(new MetaFillColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+
+ Color aColor;
+ ReadColor(aColor);
+ bool aBool(false);
+ mrStream.ReadCharAsBool(aBool);
+
+ pAction->SetColor(aColor);
+ pAction->SetSetting(aBool);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::RectHandler()
+{
+ rtl::Reference<MetaRectAction> pAction(new MetaRectAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+ pAction->SetRect(aRectangle);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PointHandler()
+{
+ rtl::Reference<MetaPointAction> pAction(new MetaPointAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ pAction->SetPoint(aPoint);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PixelHandler()
+{
+ rtl::Reference<MetaPixelAction> pAction(new MetaPixelAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Color aColor;
+ ReadColor(aColor);
+
+ pAction->SetPoint(aPoint);
+ pAction->SetColor(aColor);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::LineHandler()
+{
+ rtl::Reference<MetaLineAction> pAction(new MetaLineAction);
+
+ VersionCompatRead aCompat(mrStream);
+
+ // Version 1
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ Point aEndPoint;
+ aSerializer.readPoint(aPoint);
+ aSerializer.readPoint(aEndPoint);
+
+ pAction->SetStartPoint(aPoint);
+ pAction->SetEndPoint(aEndPoint);
+
+ // Version 2
+ if (aCompat.GetVersion() >= 2)
+ {
+ LineInfo aLineInfo;
+ ReadLineInfo(mrStream, aLineInfo);
+ pAction->SetLineInfo(aLineInfo);
+ }
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::RoundRectHandler()
+{
+ rtl::Reference<MetaRoundRectAction> pAction(new MetaRoundRectAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+ sal_uInt32 HorzRound(0);
+ sal_uInt32 VertRound(0);
+ mrStream.ReadUInt32(HorzRound).ReadUInt32(VertRound);
+
+ pAction->SetRect(aRectangle);
+ pAction->SetHorzRound(HorzRound);
+ pAction->SetVertRound(VertRound);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::EllipseHandler()
+{
+ rtl::Reference<MetaEllipseAction> pAction(new MetaEllipseAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+
+ pAction->SetRect(aRectangle);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::ArcHandler()
+{
+ rtl::Reference<MetaArcAction> pAction(new MetaArcAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Point aEndPoint;
+ aSerializer.readPoint(aEndPoint);
+
+ pAction->SetRect(aRectangle);
+ pAction->SetStartPoint(aPoint);
+ pAction->SetEndPoint(aEndPoint);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PieHandler()
+{
+ rtl::Reference<MetaPieAction> pAction(new MetaPieAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Point aEndPoint;
+ aSerializer.readPoint(aEndPoint);
+
+ pAction->SetRect(aRectangle);
+ pAction->SetStartPoint(aPoint);
+ pAction->SetEndPoint(aEndPoint);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::ChordHandler()
+{
+ rtl::Reference<MetaChordAction> pAction(new MetaChordAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRectangle;
+ aSerializer.readRectangle(aRectangle);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Point aEndPoint;
+ aSerializer.readPoint(aEndPoint);
+
+ pAction->SetRect(aRectangle);
+ pAction->SetStartPoint(aPoint);
+ pAction->SetEndPoint(aEndPoint);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PolyLineHandler()
+{
+ rtl::Reference<MetaPolyLineAction> pAction(new MetaPolyLineAction);
+
+ VersionCompatRead aCompat(mrStream);
+
+ // Version 1
+ tools::Polygon aPolygon;
+ ReadPolygon(mrStream, aPolygon);
+
+ // Version 2
+ if (aCompat.GetVersion() >= 2)
+ {
+ LineInfo aLineInfo;
+ ReadLineInfo(mrStream, aLineInfo);
+ pAction->SetLineInfo(aLineInfo);
+ }
+ if (aCompat.GetVersion() >= 3)
+ {
+ sal_uInt8 bHasPolyFlags(0);
+ mrStream.ReadUChar(bHasPolyFlags);
+ if (bHasPolyFlags)
+ aPolygon.Read(mrStream);
+ }
+ pAction->SetPolygon(aPolygon);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PolygonHandler()
+{
+ rtl::Reference<MetaPolygonAction> pAction(new MetaPolygonAction);
+
+ VersionCompatRead aCompat(mrStream);
+
+ tools::Polygon aPolygon;
+ ReadPolygon(mrStream, aPolygon); // Version 1
+
+ if (aCompat.GetVersion() >= 2) // Version 2
+ {
+ sal_uInt8 bHasPolyFlags(0);
+ mrStream.ReadUChar(bHasPolyFlags);
+ if (bHasPolyFlags)
+ aPolygon.Read(mrStream);
+ }
+
+ pAction->SetPolygon(aPolygon);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PolyPolygonHandler()
+{
+ rtl::Reference<MetaPolyPolygonAction> pAction(new MetaPolyPolygonAction);
+
+ VersionCompatRead aCompat(mrStream);
+ tools::PolyPolygon aPolyPolygon;
+ ReadPolyPolygon(mrStream, aPolyPolygon); // Version 1
+
+ if (aCompat.GetVersion() < 2) // Version 2
+ {
+ pAction->SetPolyPolygon(aPolyPolygon);
+ return pAction;
+ }
+
+ sal_uInt16 nNumberOfComplexPolygons(0);
+ mrStream.ReadUInt16(nNumberOfComplexPolygons);
+ const size_t nMinRecordSize = sizeof(sal_uInt16);
+ const size_t nMaxRecords = mrStream.remainingSize() / nMinRecordSize;
+ if (nNumberOfComplexPolygons > nMaxRecords)
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: " << nMaxRecords << " max possible entries, but "
+ << nNumberOfComplexPolygons
+ << " claimed, truncating");
+ nNumberOfComplexPolygons = nMaxRecords;
+ }
+ for (sal_uInt16 i = 0; i < nNumberOfComplexPolygons; ++i)
+ {
+ sal_uInt16 nIndex(0);
+ mrStream.ReadUInt16(nIndex);
+ tools::Polygon aPoly;
+ aPoly.Read(mrStream);
+ if (nIndex >= aPolyPolygon.Count())
+ {
+ SAL_WARN("vcl.gdi", "svm contains polygon index " << nIndex
+ << " outside possible range "
+ << aPolyPolygon.Count());
+ continue;
+ }
+ aPolyPolygon.Replace(aPoly, nIndex);
+ }
+
+ pAction->SetPolyPolygon(aPolyPolygon);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextHandler(const ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaTextAction> pAction(new MetaTextAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet);
+ sal_uInt16 nTmpIndex(0);
+ mrStream.ReadUInt16(nTmpIndex);
+ sal_uInt16 nTmpLen(0);
+ mrStream.ReadUInt16(nTmpLen);
+
+ pAction->SetPoint(aPoint);
+
+ if (aCompat.GetVersion() >= 2) // Version 2
+ aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream);
+
+ if (nTmpIndex > aStr.getLength())
+ {
+ SAL_WARN("vcl.gdi", "inconsistent offset");
+ nTmpIndex = aStr.getLength();
+ }
+
+ if (nTmpLen > aStr.getLength() - nTmpIndex)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent len");
+ nTmpLen = aStr.getLength() - nTmpIndex;
+ }
+
+ pAction->SetIndex(nTmpIndex);
+ pAction->SetLen(nTmpLen);
+
+ pAction->SetText(aStr);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextArrayHandler(const ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaTextArrayAction> pAction(new MetaTextArrayAction);
+
+ std::vector<sal_Int32> aArray;
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ pAction->SetPoint(aPoint);
+
+ OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet);
+ pAction->SetText(aStr);
+
+ sal_uInt16 nTmpIndex(0);
+ mrStream.ReadUInt16(nTmpIndex);
+
+ sal_uInt16 nTmpLen(0);
+ mrStream.ReadUInt16(nTmpLen);
+
+ sal_Int32 nAryLen(0);
+ mrStream.ReadInt32(nAryLen);
+
+ if (nTmpLen > aStr.getLength() - nTmpIndex)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent offset and len");
+ pAction->SetIndex(0);
+ pAction->SetLen(aStr.getLength());
+ return pAction;
+ }
+
+ pAction->SetIndex(nTmpIndex);
+ pAction->SetLen(nTmpLen);
+
+ if (nAryLen)
+ {
+ // #i9762#, #106172# Ensure that DX array is at least mnLen entries long
+ if (nTmpLen >= nAryLen)
+ {
+ try
+ {
+ aArray.resize(nTmpLen);
+ sal_Int32 i;
+ sal_Int32 val(0);
+ for (i = 0; i < nAryLen; i++)
+ {
+ mrStream.ReadInt32(val);
+ aArray[i] = val;
+ }
+ // #106172# setup remainder
+ for (; i < nTmpLen; i++)
+ aArray[i] = 0;
+ }
+ catch (std::bad_alloc&)
+ {
+ }
+ }
+ else
+ {
+ return pAction;
+ }
+ }
+
+ if (aCompat.GetVersion() >= 2) // Version 2
+ {
+ aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream);
+ pAction->SetText(aStr);
+
+ if (nTmpLen > aStr.getLength() - nTmpIndex)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent offset and len");
+ pAction->SetIndex(0);
+ pAction->SetLen(aStr.getLength());
+ aArray.clear();
+ }
+ }
+
+ if (!aArray.empty())
+ pAction->SetDXArray(std::move(aArray));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::StretchTextHandler(const ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaStretchTextAction> pAction(new MetaStretchTextAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet);
+ sal_uInt32 nTmpWidth(0);
+ mrStream.ReadUInt32(nTmpWidth);
+ sal_uInt16 nTmpIndex(0);
+ mrStream.ReadUInt16(nTmpIndex);
+ sal_uInt16 nTmpLen(0);
+ mrStream.ReadUInt16(nTmpLen);
+
+ pAction->SetPoint(aPoint);
+ pAction->SetWidth(nTmpWidth);
+
+ if (aCompat.GetVersion() >= 2) // Version 2
+ aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream);
+
+ if (nTmpIndex > aStr.getLength())
+ {
+ SAL_WARN("vcl.gdi", "inconsistent offset");
+ nTmpIndex = aStr.getLength();
+ }
+
+ if (nTmpLen > aStr.getLength() - nTmpIndex)
+ {
+ SAL_WARN("vcl.gdi", "inconsistent len");
+ nTmpLen = aStr.getLength() - nTmpIndex;
+ }
+
+ pAction->SetIndex(nTmpIndex);
+ pAction->SetLen(nTmpLen);
+
+ pAction->SetText(aStr);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextRectHandler(const ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaTextRectAction> pAction(new MetaTextRectAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRect;
+ aSerializer.readRectangle(aRect);
+ OUString aStr = mrStream.ReadUniOrByteString(pData->meActualCharSet);
+ sal_uInt16 nTmp(0);
+ mrStream.ReadUInt16(nTmp);
+
+ pAction->SetRect(aRect);
+ pAction->SetStyle(static_cast<DrawTextFlags>(nTmp));
+
+ if (aCompat.GetVersion() >= 2) // Version 2
+ aStr = read_uInt16_lenPrefixed_uInt16s_ToOUString(mrStream);
+
+ pAction->SetText(aStr);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextLineHandler()
+{
+ rtl::Reference<MetaTextLineAction> pAction(new MetaTextLineAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aPos;
+ aSerializer.readPoint(aPos);
+ sal_Int32 nTempWidth(0);
+ mrStream.ReadInt32(nTempWidth);
+
+ pAction->SetStartPoint(aPos);
+ pAction->SetWidth(nTempWidth);
+
+ sal_uInt32 nTempStrikeout(0);
+ mrStream.ReadUInt32(nTempStrikeout);
+ sal_uInt32 nTempUnderline(0);
+ mrStream.ReadUInt32(nTempUnderline);
+
+ pAction->SetStrikeout(static_cast<FontStrikeout>(nTempStrikeout & SAL_MAX_ENUM));
+ pAction->SetUnderline(static_cast<FontLineStyle>(nTempUnderline & SAL_MAX_ENUM));
+
+ if (aCompat.GetVersion() >= 2)
+ {
+ sal_uInt32 nTempOverline(0);
+ mrStream.ReadUInt32(nTempOverline);
+ pAction->SetOverline(static_cast<FontLineStyle>(nTempOverline & SAL_MAX_ENUM));
+ }
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpHandler()
+{
+ rtl::Reference<MetaBmpAction> pAction(new MetaBmpAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetPoint(aPoint);
+
+ return pAction;
+}
+
+namespace
+{
+void sanitizeNegativeSizeDimensions(Size& rSize)
+{
+ if (rSize.Width() < 0)
+ {
+ SAL_WARN("vcl.gdi", "sanitizeNegativeSizeDimensions: negative width");
+ rSize.setWidth(0);
+ }
+
+ if (rSize.Height() < 0)
+ {
+ SAL_WARN("vcl.gdi", "sanitizeNegativeSizeDimensions: negative height");
+ rSize.setHeight(0);
+ }
+}
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpScaleHandler()
+{
+ rtl::Reference<MetaBmpScaleAction> pAction(new MetaBmpScaleAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ Size aSz;
+ aSerializer.readSize(aSz);
+ sanitizeNegativeSizeDimensions(aSz);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetPoint(aPoint);
+ pAction->SetSize(aSz);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpScalePartHandler()
+{
+ rtl::Reference<MetaBmpScalePartAction> pAction(new MetaBmpScalePartAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ TypeSerializer aSerializer(mrStream);
+ Point aDestPoint;
+ aSerializer.readPoint(aDestPoint);
+ Size aDestSize;
+ aSerializer.readSize(aDestSize);
+ Point aSrcPoint;
+ aSerializer.readPoint(aSrcPoint);
+ Size aSrcSize;
+ aSerializer.readSize(aSrcSize);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetDestPoint(aDestPoint);
+ pAction->SetDestSize(aDestSize);
+ pAction->SetSrcPoint(aSrcPoint);
+ pAction->SetSrcSize(aSrcSize);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpExHandler()
+{
+ rtl::Reference<MetaBmpExAction> pAction(new MetaBmpExAction);
+
+ VersionCompatRead aCompat(mrStream);
+ BitmapEx aBmpEx;
+ ReadDIBBitmapEx(aBmpEx, mrStream);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ pAction->SetPoint(aPoint);
+ pAction->SetBitmapEx(aBmpEx);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpExScaleHandler()
+{
+ rtl::Reference<MetaBmpExScaleAction> pAction(new MetaBmpExScaleAction);
+
+ VersionCompatRead aCompat(mrStream);
+ BitmapEx aBmpEx;
+ ReadDIBBitmapEx(aBmpEx, mrStream);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ Size aSize;
+ aSerializer.readSize(aSize);
+ sanitizeNegativeSizeDimensions(aSize);
+
+ pAction->SetBitmapEx(aBmpEx);
+ pAction->SetPoint(aPoint);
+ pAction->SetSize(aSize);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::BmpExScalePartHandler()
+{
+ rtl::Reference<MetaBmpExScalePartAction> pAction(new MetaBmpExScalePartAction);
+
+ VersionCompatRead aCompat(mrStream);
+ BitmapEx aBmpEx;
+ ReadDIBBitmapEx(aBmpEx, mrStream);
+ TypeSerializer aSerializer(mrStream);
+ Point aDstPoint;
+ aSerializer.readPoint(aDstPoint);
+ Size aDstSize;
+ aSerializer.readSize(aDstSize);
+ Point aSrcPoint;
+ aSerializer.readPoint(aSrcPoint);
+ Size aSrcSize;
+ aSerializer.readSize(aSrcSize);
+
+ pAction->SetBitmapEx(aBmpEx);
+ pAction->SetDestPoint(aDstPoint);
+ pAction->SetDestSize(aDstSize);
+ pAction->SetSrcPoint(aSrcPoint);
+ pAction->SetSrcSize(aSrcSize);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::MaskHandler()
+{
+ rtl::Reference<MetaMaskAction> pAction(new MetaMaskAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetPoint(aPoint);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::MaskScaleHandler()
+{
+ rtl::Reference<MetaMaskScaleAction> pAction(new MetaMaskScaleAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Size aSize;
+ aSerializer.readSize(aSize);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetPoint(aPoint);
+ pAction->SetSize(aSize);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::MaskScalePartHandler()
+{
+ rtl::Reference<MetaMaskScalePartAction> pAction(new MetaMaskScalePartAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Bitmap aBmp;
+ ReadDIB(aBmp, mrStream, true);
+ Color aColor;
+ ReadColor(aColor);
+ TypeSerializer aSerializer(mrStream);
+ Point aDstPt;
+ aSerializer.readPoint(aDstPt);
+ Size aDstSz;
+ aSerializer.readSize(aDstSz);
+ Point aSrcPt;
+ aSerializer.readPoint(aSrcPt);
+ Size aSrcSz;
+ aSerializer.readSize(aSrcSz);
+
+ pAction->SetBitmap(aBmp);
+ pAction->SetColor(aColor);
+ pAction->SetDestPoint(aDstPt);
+ pAction->SetDestSize(aDstSz);
+ pAction->SetSrcPoint(aSrcPt);
+ pAction->SetSrcSize(aSrcSz);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::GradientHandler()
+{
+ rtl::Reference<MetaGradientAction> pAction(new MetaGradientAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ tools::Rectangle aRect;
+ aSerializer.readRectangle(aRect);
+ Gradient aGradient;
+ aSerializer.readGradient(aGradient);
+
+ pAction->SetRect(aRect);
+ pAction->SetGradient(aGradient);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::GradientExHandler()
+{
+ rtl::Reference<MetaGradientExAction> pAction(new MetaGradientExAction);
+
+ VersionCompatRead aCompat(mrStream);
+ tools::PolyPolygon aPolyPoly;
+ ReadPolyPolygon(mrStream, aPolyPoly);
+ TypeSerializer aSerializer(mrStream);
+ Gradient aGradient;
+ aSerializer.readGradient(aGradient);
+
+ pAction->SetGradient(aGradient);
+ pAction->SetPolyPolygon(aPolyPoly);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::HatchHandler()
+{
+ rtl::Reference<MetaHatchAction> pAction(new MetaHatchAction);
+
+ VersionCompatRead aCompat(mrStream);
+ tools::PolyPolygon aPolyPoly;
+ ReadPolyPolygon(mrStream, aPolyPoly);
+ Hatch aHatch;
+ ReadHatch(mrStream, aHatch);
+
+ pAction->SetPolyPolygon(aPolyPoly);
+ pAction->SetHatch(aHatch);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::WallpaperHandler()
+{
+ rtl::Reference<MetaWallpaperAction> pAction(new MetaWallpaperAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Wallpaper aWallpaper;
+ ReadWallpaper(mrStream, aWallpaper);
+
+ pAction->SetWallpaper(aWallpaper);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::ClipRegionHandler()
+{
+ rtl::Reference<MetaClipRegionAction> pAction(new MetaClipRegionAction);
+
+ VersionCompatRead aCompat(mrStream);
+ vcl::Region aRegion;
+ ReadRegion(mrStream, aRegion);
+ bool aClip(false);
+ mrStream.ReadCharAsBool(aClip);
+
+ pAction->SetRegion(aRegion);
+ pAction->SetClipping(aClip);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::ISectRectClipRegionHandler()
+{
+ rtl::Reference<MetaISectRectClipRegionAction> pAction(new MetaISectRectClipRegionAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+ tools::Rectangle aRect;
+ aSerializer.readRectangle(aRect);
+
+ pAction->SetRect(aRect);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::ISectRegionClipRegionHandler()
+{
+ rtl::Reference<MetaISectRegionClipRegionAction> pAction(new MetaISectRegionClipRegionAction);
+
+ VersionCompatRead aCompat(mrStream);
+ vcl::Region aRegion;
+ ReadRegion(mrStream, aRegion);
+ pAction->SetRegion(aRegion);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::MoveClipRegionHandler()
+{
+ rtl::Reference<MetaMoveClipRegionAction> pAction(new MetaMoveClipRegionAction);
+
+ VersionCompatRead aCompat(mrStream);
+ sal_Int32 nTmpHM(0), nTmpVM(0);
+ mrStream.ReadInt32(nTmpHM).ReadInt32(nTmpVM);
+
+ pAction->SetHorzMove(nTmpHM);
+ pAction->SetVertMove(nTmpVM);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextColorHandler()
+{
+ rtl::Reference<MetaTextColorAction> pAction(new MetaTextColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Color aColor;
+ ReadColor(aColor);
+
+ pAction->SetColor(aColor);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextFillColorHandler()
+{
+ rtl::Reference<MetaTextFillColorAction> pAction(new MetaTextFillColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Color aColor;
+ ReadColor(aColor);
+ bool bSet(false);
+ mrStream.ReadCharAsBool(bSet);
+
+ pAction->SetColor(aColor);
+ pAction->SetSetting(bSet);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextLineColorHandler()
+{
+ rtl::Reference<MetaTextLineColorAction> pAction(new MetaTextLineColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Color aColor;
+ ReadColor(aColor);
+ bool bSet(false);
+ mrStream.ReadCharAsBool(bSet);
+
+ pAction->SetColor(aColor);
+ pAction->SetSetting(bSet);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::OverlineColorHandler()
+{
+ rtl::Reference<MetaOverlineColorAction> pAction(new MetaOverlineColorAction);
+
+ VersionCompatRead aCompat(mrStream);
+ Color aColor;
+ ReadColor(aColor);
+ bool bSet(false);
+ mrStream.ReadCharAsBool(bSet);
+
+ pAction->SetColor(aColor);
+ pAction->SetSetting(bSet);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextAlignHandler()
+{
+ rtl::Reference<MetaTextAlignAction> pAction(new MetaTextAlignAction);
+
+ VersionCompatRead aCompat(mrStream);
+ sal_uInt16 nTmp16(0);
+ mrStream.ReadUInt16(nTmp16);
+
+ pAction->SetTextAlign(static_cast<TextAlign>(nTmp16));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::MapModeHandler()
+{
+ rtl::Reference<MetaMapModeAction> pAction(new MetaMapModeAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+ MapMode aMapMode;
+ aSerializer.readMapMode(aMapMode);
+
+ pAction->SetMapMode(aMapMode);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::FontHandler(ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaFontAction> pAction(new MetaFontAction);
+
+ VersionCompatRead aCompat(mrStream);
+ vcl::Font aFont;
+ ReadFont(mrStream, aFont);
+ pData->meActualCharSet = aFont.GetCharSet();
+ if (pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW)
+ pData->meActualCharSet = osl_getThreadTextEncoding();
+
+ pAction->SetFont(aFont);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PushHandler()
+{
+ rtl::Reference<MetaPushAction> pAction(new MetaPushAction);
+
+ VersionCompatRead aCompat(mrStream);
+ sal_uInt16 nTmp(0);
+ mrStream.ReadUInt16(nTmp);
+
+ pAction->SetPushFlags(static_cast<vcl::PushFlags>(nTmp));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::PopHandler()
+{
+ rtl::Reference<MetaPopAction> pAction(new MetaPopAction);
+
+ VersionCompatRead aCompat(mrStream);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::RasterOpHandler()
+{
+ rtl::Reference<MetaRasterOpAction> pAction(new MetaRasterOpAction);
+
+ sal_uInt16 nTmp16(0);
+
+ VersionCompatRead aCompat(mrStream);
+ mrStream.ReadUInt16(nTmp16);
+
+ pAction->SetRasterOp(static_cast<RasterOp>(nTmp16));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TransparentHandler()
+{
+ rtl::Reference<MetaTransparentAction> pAction(new MetaTransparentAction);
+
+ VersionCompatRead aCompat(mrStream);
+ tools::PolyPolygon aPolyPoly;
+ ReadPolyPolygon(mrStream, aPolyPoly);
+ sal_uInt16 nTransPercent(0);
+ mrStream.ReadUInt16(nTransPercent);
+
+ pAction->SetPolyPolygon(aPolyPoly);
+ pAction->SetTransparence(nTransPercent);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::FloatTransparentHandler(ImplMetaReadData* pData)
+{
+ rtl::Reference<MetaFloatTransparentAction> pAction(new MetaFloatTransparentAction);
+
+ VersionCompatRead aCompat(mrStream);
+ GDIMetaFile aMtf;
+ SvmReader aReader(mrStream);
+ aReader.Read(aMtf, pData);
+ TypeSerializer aSerializer(mrStream);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+
+ Size aSize;
+ aSerializer.readSize(aSize);
+ sanitizeNegativeSizeDimensions(aSize);
+
+ Gradient aGradient;
+ aSerializer.readGradient(aGradient);
+
+ pAction->SetGDIMetaFile(aMtf);
+ pAction->SetPoint(aPoint);
+ pAction->SetSize(aSize);
+ pAction->SetGradient(aGradient);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::EPSHandler()
+{
+ rtl::Reference<MetaEPSAction> pAction(new MetaEPSAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+ GfxLink aGfxLink;
+ aSerializer.readGfxLink(aGfxLink);
+ Point aPoint;
+ aSerializer.readPoint(aPoint);
+ Size aSize;
+ aSerializer.readSize(aSize);
+ GDIMetaFile aSubst;
+ Read(aSubst);
+
+ pAction->SetLink(aGfxLink);
+ pAction->SetPoint(aPoint);
+ pAction->SetSize(aSize);
+ pAction->SetSubstitute(aSubst);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::RefPointHandler()
+{
+ rtl::Reference<MetaRefPointAction> pAction(new MetaRefPointAction);
+
+ VersionCompatRead aCompat(mrStream);
+ TypeSerializer aSerializer(mrStream);
+
+ Point aRefPoint;
+ aSerializer.readPoint(aRefPoint);
+ bool bSet(false);
+ mrStream.ReadCharAsBool(bSet);
+
+ pAction->SetRefPoint(aRefPoint);
+ pAction->SetSetting(bSet);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::CommentHandler()
+{
+ rtl::Reference<MetaCommentAction> pAction(new MetaCommentAction);
+
+ VersionCompatRead aCompat(mrStream);
+ OString aComment;
+ aComment = read_uInt16_lenPrefixed_uInt8s_ToOString(mrStream);
+ sal_Int32 nValue(0);
+ sal_uInt32 nDataSize(0);
+ mrStream.ReadInt32(nValue).ReadUInt32(nDataSize);
+
+ if (nDataSize > mrStream.remainingSize())
+ {
+ SAL_WARN("vcl.gdi", "Parsing error: " << mrStream.remainingSize() << " available data, but "
+ << nDataSize << " claimed, truncating");
+ nDataSize = mrStream.remainingSize();
+ }
+
+ SAL_INFO("vcl.gdi", "MetaCommentAction::Read " << aComment);
+
+ std::unique_ptr<sal_uInt8[]> pData;
+ pData.reset();
+
+ if (nDataSize)
+ {
+ pData.reset(new sal_uInt8[nDataSize]);
+ mrStream.ReadBytes(pData.get(), nDataSize);
+ }
+
+ pAction->SetComment(aComment);
+ pAction->SetDataSize(nDataSize);
+ pAction->SetValue(nValue);
+ pAction->SetData(pData.get(), nDataSize);
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::LayoutModeHandler()
+{
+ rtl::Reference<MetaLayoutModeAction> pAction(new MetaLayoutModeAction);
+
+ VersionCompatRead aCompat(mrStream);
+ sal_uInt32 tmp(0);
+ mrStream.ReadUInt32(tmp);
+
+ pAction->SetLayoutMode(static_cast<vcl::text::ComplexTextLayoutFlags>(tmp));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::TextLanguageHandler()
+{
+ rtl::Reference<MetaTextLanguageAction> pAction(new MetaTextLanguageAction);
+
+ VersionCompatRead aCompat(mrStream);
+ sal_uInt16 nTmp = 0;
+ mrStream.ReadUInt16(nTmp);
+
+ pAction->SetTextLanguage(static_cast<LanguageType>(nTmp));
+
+ return pAction;
+}
+
+rtl::Reference<MetaAction> SvmReader::DefaultHandler()
+{
+ return rtl::Reference<MetaAction>(new MetaAction);
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/filter/svm/SvmWriter.cxx b/vcl/source/filter/svm/SvmWriter.cxx
new file mode 100644
index 000000000..118db1325
--- /dev/null
+++ b/vcl/source/filter/svm/SvmWriter.cxx
@@ -0,0 +1,1421 @@
+/* -*- 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/filter/SvmWriter.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <vcl/dibtools.hxx>
+
+#include <tools/vcompat.hxx>
+
+#include <osl/thread.h>
+
+SvmWriter::SvmWriter(SvStream& rIStm)
+ : mrStream(rIStm)
+{
+}
+
+void SvmWriter::WriteColor(::Color aColor)
+{
+ mrStream.WriteUInt32(static_cast<sal_uInt32>(aColor));
+}
+
+SvStream& SvmWriter::Write(const GDIMetaFile& rMetaFile)
+{
+ const SvStreamCompressFlags nStmCompressMode = mrStream.GetCompressMode();
+ SvStreamEndian nOldFormat = mrStream.GetEndian();
+
+ mrStream.SetEndian(SvStreamEndian::LITTLE);
+ mrStream.WriteBytes("VCLMTF", 6);
+
+ {
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ mrStream.WriteUInt32(static_cast<sal_uInt32>(nStmCompressMode));
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeMapMode(rMetaFile.GetPrefMapMode());
+ aSerializer.writeSize(rMetaFile.GetPrefSize());
+ mrStream.WriteUInt32(rMetaFile.GetActionSize());
+ } // VersionCompatWrite dtor writes stuff into the header
+
+ ImplMetaWriteData aWriteData;
+
+ aWriteData.meActualCharSet = mrStream.GetStreamCharSet();
+
+ MetaAction* pAct = const_cast<GDIMetaFile&>(rMetaFile).FirstAction();
+ while (pAct)
+ {
+ MetaActionHandler(pAct, &aWriteData);
+ pAct = const_cast<GDIMetaFile&>(rMetaFile).NextAction();
+ }
+
+ mrStream.SetEndian(nOldFormat);
+
+ return mrStream;
+}
+
+BitmapChecksum SvmWriter::GetChecksum(const GDIMetaFile& rMetaFile)
+{
+ SvMemoryStream aMemStm(65535, 65535);
+ ImplMetaWriteData aWriteData;
+ SVBT16 aBT16;
+ SVBT32 aBT32;
+ BitmapChecksumOctetArray aBCOA;
+ BitmapChecksum nCrc = 0;
+
+ aWriteData.meActualCharSet = aMemStm.GetStreamCharSet();
+
+ for (size_t i = 0, nObjCount = rMetaFile.GetActionSize(); i < nObjCount; i++)
+ {
+ MetaAction* pAction = rMetaFile.GetAction(i);
+
+ switch (pAction->GetType())
+ {
+ case MetaActionType::BMP:
+ {
+ MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::BMPSCALE:
+ {
+ MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::BMPSCALEPART:
+ {
+ MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::BMPEX:
+ {
+ MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALE:
+ {
+ MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALEPART:
+ {
+ MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmapEx().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::MASK:
+ {
+ MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::MASKSCALE:
+ {
+ MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::MASKSCALEPART:
+ {
+ MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pAction);
+
+ ShortToSVBT16(static_cast<sal_uInt16>(pAct->GetType()), aBT16);
+ nCrc = vcl_get_checksum(nCrc, aBT16, 2);
+
+ BCToBCOA(pAct->GetBitmap().GetChecksum(), aBCOA);
+ nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE);
+
+ UInt32ToSVBT32(sal_uInt32(pAct->GetColor()), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetDestSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().X(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcPoint().Y(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Width(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+
+ Int32ToSVBT32(pAct->GetSrcSize().Height(), aBT32);
+ nCrc = vcl_get_checksum(nCrc, aBT32, 4);
+ }
+ break;
+
+ case MetaActionType::EPS:
+ {
+ MetaEPSAction* pAct = static_cast<MetaEPSAction*>(pAction);
+ nCrc = vcl_get_checksum(nCrc, pAct->GetLink().GetData(),
+ pAct->GetLink().GetDataSize());
+ }
+ break;
+
+ case MetaActionType::CLIPREGION:
+ {
+ MetaClipRegionAction& rAct = static_cast<MetaClipRegionAction&>(*pAction);
+ const vcl::Region& rRegion = rAct.GetRegion();
+
+ if (rRegion.HasPolyPolygonOrB2DPolyPolygon())
+ {
+ // It has shown that this is a possible bottleneck for checksum calculation.
+ // In worst case a very expensive RegionHandle representation gets created.
+ // In this case it's cheaper to use the PolyPolygon
+ const basegfx::B2DPolyPolygon aPolyPolygon(rRegion.GetAsB2DPolyPolygon());
+ SVBT64 aSVBT64;
+
+ for (auto const& rPolygon : aPolyPolygon)
+ {
+ const sal_uInt32 nPointCount(rPolygon.count());
+ const bool bControl(rPolygon.areControlPointsUsed());
+
+ for (sal_uInt32 b(0); b < nPointCount; b++)
+ {
+ const basegfx::B2DPoint aPoint(rPolygon.getB2DPoint(b));
+
+ DoubleToSVBT64(aPoint.getX(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+ DoubleToSVBT64(aPoint.getY(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+
+ if (bControl)
+ {
+ if (rPolygon.isPrevControlPointUsed(b))
+ {
+ const basegfx::B2DPoint aCtrl(rPolygon.getPrevControlPoint(b));
+
+ DoubleToSVBT64(aCtrl.getX(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+ DoubleToSVBT64(aCtrl.getY(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+ }
+
+ if (rPolygon.isNextControlPointUsed(b))
+ {
+ const basegfx::B2DPoint aCtrl(rPolygon.getNextControlPoint(b));
+
+ DoubleToSVBT64(aCtrl.getX(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+ DoubleToSVBT64(aCtrl.getY(), aSVBT64);
+ nCrc = vcl_get_checksum(nCrc, aSVBT64, 8);
+ }
+ }
+ }
+ }
+
+ sal_uInt8 tmp = static_cast<sal_uInt8>(rAct.IsClipping());
+ nCrc = vcl_get_checksum(nCrc, &tmp, 1);
+ }
+ else
+ {
+ SvmWriter aWriter(aMemStm);
+ aWriter.MetaActionHandler(pAction, &aWriteData);
+ nCrc = vcl_get_checksum(nCrc, aMemStm.GetData(), aMemStm.Tell());
+ aMemStm.Seek(0);
+ }
+ }
+ break;
+
+ default:
+ {
+ SvmWriter aWriter(aMemStm);
+ aWriter.MetaActionHandler(pAction, &aWriteData);
+ nCrc = vcl_get_checksum(nCrc, aMemStm.GetData(), aMemStm.Tell());
+ aMemStm.Seek(0);
+ }
+ break;
+ }
+ }
+
+ return nCrc;
+}
+
+void SvmWriter::MetaActionHandler(MetaAction* pAction, ImplMetaWriteData* pData)
+{
+ MetaActionType nType = pAction->GetType();
+
+ switch (nType)
+ {
+ case MetaActionType::NONE:
+ {
+ ActionHandler(pAction);
+ }
+ break;
+
+ case MetaActionType::PIXEL:
+ {
+ auto* pMetaAction = static_cast<MetaPixelAction*>(pAction);
+ PixelHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::POINT:
+ {
+ auto pMetaAction = static_cast<MetaPointAction*>(pAction);
+ PointHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::LINE:
+ {
+ auto* pMetaAction = static_cast<MetaLineAction*>(pAction);
+ LineHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::RECT:
+ {
+ auto* pMetaAction = static_cast<MetaRectAction*>(pAction);
+ RectHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::ROUNDRECT:
+ {
+ auto* pMetaAction = static_cast<MetaRoundRectAction*>(pAction);
+ RoundRectHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::ELLIPSE:
+ {
+ auto* pMetaAction = static_cast<MetaEllipseAction*>(pAction);
+ EllipseHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::ARC:
+ {
+ auto* pMetaAction = static_cast<MetaArcAction*>(pAction);
+ ArcHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::PIE:
+ {
+ auto* pMetaAction = static_cast<MetaPieAction*>(pAction);
+ PieHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::CHORD:
+ {
+ auto* pMetaAction = static_cast<MetaChordAction*>(pAction);
+ ChordHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::POLYLINE:
+ {
+ auto* pMetaAction = static_cast<MetaPolyLineAction*>(pAction);
+ PolyLineHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::POLYGON:
+ {
+ auto* pMetaAction = static_cast<MetaPolygonAction*>(pAction);
+ PolygonHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::POLYPOLYGON:
+ {
+ auto* pMetaAction = static_cast<MetaPolyPolygonAction*>(pAction);
+ PolyPolygonHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXT:
+ {
+ auto* pMetaAction = static_cast<MetaTextAction*>(pAction);
+ TextHandler(pMetaAction, pData);
+ }
+ break;
+
+ case MetaActionType::TEXTARRAY:
+ {
+ auto* pMetaAction = static_cast<MetaTextArrayAction*>(pAction);
+ TextArrayHandler(pMetaAction, pData);
+ }
+ break;
+
+ case MetaActionType::STRETCHTEXT:
+ {
+ auto* pMetaAction = static_cast<MetaStretchTextAction*>(pAction);
+ StretchTextHandler(pMetaAction, pData);
+ }
+ break;
+
+ case MetaActionType::TEXTRECT:
+ {
+ auto* pMetaAction = static_cast<MetaTextRectAction*>(pAction);
+ TextRectHandler(pMetaAction, pData);
+ }
+ break;
+
+ case MetaActionType::TEXTLINE:
+ {
+ auto* pMetaAction = static_cast<MetaTextLineAction*>(pAction);
+ TextLineHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMP:
+ {
+ auto* pMetaAction = static_cast<MetaBmpAction*>(pAction);
+ BmpHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMPSCALE:
+ {
+ auto* pMetaAction = static_cast<MetaBmpScaleAction*>(pAction);
+ BmpScaleHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMPSCALEPART:
+ {
+ auto* pMetaAction = static_cast<MetaBmpScalePartAction*>(pAction);
+ BmpScalePartHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMPEX:
+ {
+ auto* pMetaAction = static_cast<MetaBmpExAction*>(pAction);
+ BmpExHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALE:
+ {
+ auto* pMetaAction = static_cast<MetaBmpExScaleAction*>(pAction);
+ BmpExScaleHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALEPART:
+ {
+ auto* pMetaAction = static_cast<MetaBmpExScalePartAction*>(pAction);
+ BmpExScalePartHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::MASK:
+ {
+ auto* pMetaAction = static_cast<MetaMaskAction*>(pAction);
+ MaskHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::MASKSCALE:
+ {
+ auto* pMetaAction = static_cast<MetaMaskScaleAction*>(pAction);
+ MaskScaleHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::MASKSCALEPART:
+ {
+ auto* pMetaAction = static_cast<MetaMaskScalePartAction*>(pAction);
+ MaskScalePartHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::GRADIENT:
+ {
+ auto* pMetaAction = static_cast<MetaGradientAction*>(pAction);
+ GradientHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::GRADIENTEX:
+ {
+ auto* pMetaAction = static_cast<MetaGradientExAction*>(pAction);
+ GradientExHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::HATCH:
+ {
+ auto* pMetaAction = static_cast<MetaHatchAction*>(pAction);
+ HatchHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::WALLPAPER:
+ {
+ auto* pMetaAction = static_cast<MetaWallpaperAction*>(pAction);
+ WallpaperHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::CLIPREGION:
+ {
+ auto* pMetaAction = static_cast<MetaClipRegionAction*>(pAction);
+ ClipRegionHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::ISECTRECTCLIPREGION:
+ {
+ auto* pMetaAction = static_cast<MetaISectRectClipRegionAction*>(pAction);
+ ISectRectClipRegionHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::ISECTREGIONCLIPREGION:
+ {
+ auto* pMetaAction = static_cast<MetaISectRegionClipRegionAction*>(pAction);
+ ISectRegionClipRegionHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::MOVECLIPREGION:
+ {
+ auto* pMetaAction = static_cast<MetaMoveClipRegionAction*>(pAction);
+ MoveClipRegionHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::LINECOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaLineColorAction*>(pAction);
+ LineColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::FILLCOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaFillColorAction*>(pAction);
+ FillColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXTCOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaTextColorAction*>(pAction);
+ TextColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXTFILLCOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaTextFillColorAction*>(pAction);
+ TextFillColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXTLINECOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaTextLineColorAction*>(pAction);
+ TextLineColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::OVERLINECOLOR:
+ {
+ auto* pMetaAction = static_cast<MetaOverlineColorAction*>(pAction);
+ OverlineColorHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXTALIGN:
+ {
+ auto* pMetaAction = static_cast<MetaTextAlignAction*>(pAction);
+ TextAlignHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::MAPMODE:
+ {
+ auto* pMetaAction = static_cast<MetaMapModeAction*>(pAction);
+ MapModeHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::FONT:
+ {
+ auto* pMetaAction = static_cast<MetaFontAction*>(pAction);
+ FontHandler(pMetaAction, pData);
+ }
+ break;
+
+ case MetaActionType::PUSH:
+ {
+ auto* pMetaAction = static_cast<MetaPushAction*>(pAction);
+ PushHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::POP:
+ {
+ auto* pMetaAction = static_cast<MetaPopAction*>(pAction);
+ PopHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::RASTEROP:
+ {
+ auto* pMetaAction = static_cast<MetaRasterOpAction*>(pAction);
+ RasterOpHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::Transparent:
+ {
+ auto* pMetaAction = static_cast<MetaTransparentAction*>(pAction);
+ TransparentHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::FLOATTRANSPARENT:
+ {
+ auto* pMetaAction = static_cast<MetaFloatTransparentAction*>(pAction);
+ FloatTransparentHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::EPS:
+ {
+ auto* pMetaAction = static_cast<MetaEPSAction*>(pAction);
+ EPSHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::REFPOINT:
+ {
+ auto* pMetaAction = static_cast<MetaRefPointAction*>(pAction);
+ RefPointHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::COMMENT:
+ {
+ auto* pMetaAction = static_cast<MetaCommentAction*>(pAction);
+ CommentHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::LAYOUTMODE:
+ {
+ auto* pMetaAction = static_cast<MetaLayoutModeAction*>(pAction);
+ LayoutModeHandler(pMetaAction);
+ }
+ break;
+
+ case MetaActionType::TEXTLANGUAGE:
+ {
+ auto* pMetaAction = static_cast<MetaTextLanguageAction*>(pAction);
+ TextLanguageHandler(pMetaAction);
+ }
+ break;
+ }
+}
+
+void SvmWriter::ActionHandler(const MetaAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+}
+
+void SvmWriter::PixelHandler(const MetaPixelAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ WriteColor(pAction->GetColor());
+}
+
+void SvmWriter::PointHandler(const MetaPointAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+}
+
+void SvmWriter::LineHandler(const MetaLineAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+
+ // Version 1
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetStartPoint());
+ aSerializer.writePoint(pAction->GetEndPoint());
+ // Version 2
+ WriteLineInfo(mrStream, pAction->GetLineInfo());
+}
+
+void SvmWriter::RectHandler(const MetaRectAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+}
+
+void SvmWriter::RoundRectHandler(const MetaRoundRectAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ mrStream.WriteUInt32(pAction->GetHorzRound()).WriteUInt32(pAction->GetVertRound());
+}
+
+void SvmWriter::EllipseHandler(const MetaEllipseAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+}
+
+void SvmWriter::ArcHandler(const MetaArcAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ aSerializer.writePoint(pAction->GetStartPoint());
+ aSerializer.writePoint(pAction->GetEndPoint());
+}
+
+void SvmWriter::PieHandler(const MetaPieAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ aSerializer.writePoint(pAction->GetStartPoint());
+ aSerializer.writePoint(pAction->GetEndPoint());
+}
+
+void SvmWriter::ChordHandler(const MetaChordAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ aSerializer.writePoint(pAction->GetStartPoint());
+ aSerializer.writePoint(pAction->GetEndPoint());
+}
+
+void SvmWriter::PolyLineHandler(const MetaPolyLineAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 3);
+
+ tools::Polygon aSimplePoly;
+ pAction->GetPolygon().AdaptiveSubdivide(aSimplePoly);
+
+ WritePolygon(mrStream, aSimplePoly); // Version 1
+ WriteLineInfo(mrStream, pAction->GetLineInfo()); // Version 2
+
+ bool bHasPolyFlags = pAction->GetPolygon().HasFlags(); // Version 3
+ mrStream.WriteBool(bHasPolyFlags);
+ if (bHasPolyFlags)
+ pAction->GetPolygon().Write(mrStream);
+}
+
+void SvmWriter::PolygonHandler(const MetaPolygonAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+
+ tools::Polygon aSimplePoly; // Version 1
+ pAction->GetPolygon().AdaptiveSubdivide(aSimplePoly);
+ WritePolygon(mrStream, aSimplePoly);
+
+ bool bHasPolyFlags = pAction->GetPolygon().HasFlags(); // Version 2
+ mrStream.WriteBool(bHasPolyFlags);
+ if (bHasPolyFlags)
+ pAction->GetPolygon().Write(mrStream);
+}
+
+void SvmWriter::PolyPolygonHandler(const MetaPolyPolygonAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+
+ sal_uInt16 nNumberOfComplexPolygons = 0;
+ sal_uInt16 i, nPolyCount = pAction->GetPolyPolygon().Count();
+
+ tools::Polygon aSimplePoly; // Version 1
+ mrStream.WriteUInt16(nPolyCount);
+ for (i = 0; i < nPolyCount; i++)
+ {
+ const tools::Polygon& rPoly = pAction->GetPolyPolygon().GetObject(i);
+ if (rPoly.HasFlags())
+ nNumberOfComplexPolygons++;
+ rPoly.AdaptiveSubdivide(aSimplePoly);
+ WritePolygon(mrStream, aSimplePoly);
+ }
+
+ mrStream.WriteUInt16(nNumberOfComplexPolygons); // Version 2
+ for (i = 0; nNumberOfComplexPolygons && (i < nPolyCount); i++)
+ {
+ const tools::Polygon& rPoly = pAction->GetPolyPolygon().GetObject(i);
+ if (rPoly.HasFlags())
+ {
+ mrStream.WriteUInt16(i);
+ rPoly.Write(mrStream);
+
+ nNumberOfComplexPolygons--;
+ }
+ }
+}
+
+void SvmWriter::TextHandler(const MetaTextAction* pAction, const ImplMetaWriteData* pData)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet);
+ mrStream.WriteUInt16(pAction->GetIndex());
+ mrStream.WriteUInt16(pAction->GetLen());
+
+ write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2
+}
+
+void SvmWriter::TextArrayHandler(const MetaTextArrayAction* pAction, const ImplMetaWriteData* pData)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ const std::vector<sal_Int32>& rDXArray = pAction->GetDXArray();
+
+ const sal_Int32 nAryLen = !rDXArray.empty() ? pAction->GetLen() : 0;
+
+ VersionCompatWrite aCompat(mrStream, 2);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet);
+ mrStream.WriteUInt16(pAction->GetIndex());
+ mrStream.WriteUInt16(pAction->GetLen());
+ mrStream.WriteInt32(nAryLen);
+
+ for (sal_Int32 i = 0; i < nAryLen; ++i)
+ mrStream.WriteInt32(rDXArray[i]);
+
+ write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2
+}
+
+void SvmWriter::StretchTextHandler(const MetaStretchTextAction* pAction,
+ const ImplMetaWriteData* pData)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet);
+ mrStream.WriteUInt32(pAction->GetWidth());
+ mrStream.WriteUInt16(pAction->GetIndex());
+ mrStream.WriteUInt16(pAction->GetLen());
+
+ write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2
+}
+
+void SvmWriter::TextRectHandler(const MetaTextRectAction* pAction, const ImplMetaWriteData* pData)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ mrStream.WriteUniOrByteString(pAction->GetText(), pData->meActualCharSet);
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetStyle()));
+
+ write_uInt16_lenPrefixed_uInt16s_FromOUString(mrStream, pAction->GetText()); // version 2
+}
+
+void SvmWriter::TextLineHandler(const MetaTextLineAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+
+ VersionCompatWrite aCompat(mrStream, 2);
+
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetStartPoint());
+
+ mrStream.WriteInt32(pAction->GetWidth());
+ mrStream.WriteUInt32(pAction->GetStrikeout());
+ mrStream.WriteUInt32(pAction->GetUnderline());
+ // new in version 2
+ mrStream.WriteUInt32(pAction->GetOverline());
+}
+
+void SvmWriter::BmpHandler(const MetaBmpAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ }
+}
+
+void SvmWriter::BmpScaleHandler(const MetaBmpScaleAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ aSerializer.writeSize(pAction->GetSize());
+ }
+}
+
+void SvmWriter::BmpScalePartHandler(const MetaBmpScalePartAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetDestPoint());
+ aSerializer.writeSize(pAction->GetDestSize());
+ aSerializer.writePoint(pAction->GetSrcPoint());
+ aSerializer.writeSize(pAction->GetSrcSize());
+ }
+}
+
+void SvmWriter::BmpExHandler(const MetaBmpExAction* pAction)
+{
+ if (!pAction->GetBitmapEx().GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ }
+}
+
+void SvmWriter::BmpExScaleHandler(const MetaBmpExScaleAction* pAction)
+{
+ if (!pAction->GetBitmapEx().GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ aSerializer.writeSize(pAction->GetSize());
+ }
+}
+
+void SvmWriter::BmpExScalePartHandler(const MetaBmpExScalePartAction* pAction)
+{
+ if (!pAction->GetBitmapEx().GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIBBitmapEx(pAction->GetBitmapEx(), mrStream);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetDestPoint());
+ aSerializer.writeSize(pAction->GetDestSize());
+ aSerializer.writePoint(pAction->GetSrcPoint());
+ aSerializer.writeSize(pAction->GetSrcSize());
+ }
+}
+
+void SvmWriter::MaskHandler(const MetaMaskAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ }
+}
+
+void SvmWriter::MaskScaleHandler(const MetaMaskScaleAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ aSerializer.writeSize(pAction->GetSize());
+ }
+}
+
+void SvmWriter::MaskScalePartHandler(const MetaMaskScalePartAction* pAction)
+{
+ if (!pAction->GetBitmap().IsEmpty())
+ {
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteDIB(pAction->GetBitmap(), mrStream, false, true);
+ WriteColor(pAction->GetColor());
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetDestPoint());
+ aSerializer.writeSize(pAction->GetDestSize());
+ aSerializer.writePoint(pAction->GetSrcPoint());
+ aSerializer.writeSize(pAction->GetSrcSize());
+ }
+}
+
+void SvmWriter::GradientHandler(const MetaGradientAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+ aSerializer.writeGradient(pAction->GetGradient());
+}
+
+void SvmWriter::GradientExHandler(const MetaGradientExAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ // #i105373# see comment at MetaTransparentAction::Write
+ tools::PolyPolygon aNoCurvePolyPolygon;
+ pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ WritePolyPolygon(mrStream, aNoCurvePolyPolygon);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeGradient(pAction->GetGradient());
+}
+
+void SvmWriter::HatchHandler(const MetaHatchAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ // #i105373# see comment at MetaTransparentAction::Write
+ tools::PolyPolygon aNoCurvePolyPolygon;
+ pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ WritePolyPolygon(mrStream, aNoCurvePolyPolygon);
+ WriteHatch(mrStream, pAction->GetHatch());
+}
+
+void SvmWriter::WallpaperHandler(const MetaWallpaperAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ WriteWallpaper(mrStream, pAction->GetWallpaper());
+}
+
+void SvmWriter::ClipRegionHandler(const MetaClipRegionAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteRegion(mrStream, pAction->GetRegion());
+ mrStream.WriteBool(pAction->IsClipping());
+}
+
+void SvmWriter::ISectRectClipRegionHandler(const MetaISectRectClipRegionAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeRectangle(pAction->GetRect());
+}
+
+void SvmWriter::ISectRegionClipRegionHandler(const MetaISectRegionClipRegionAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteRegion(mrStream, pAction->GetRegion());
+}
+
+void SvmWriter::MoveClipRegionHandler(const MetaMoveClipRegionAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteInt32(pAction->GetHorzMove()).WriteInt32(pAction->GetVertMove());
+}
+
+void SvmWriter::LineColorHandler(const MetaLineColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::FillColorHandler(const MetaFillColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::TextColorHandler(const MetaTextColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+}
+
+void SvmWriter::TextFillColorHandler(const MetaTextFillColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::TextLineColorHandler(const MetaTextLineColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::OverlineColorHandler(const MetaOverlineColorAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteColor(pAction->GetColor());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::TextAlignHandler(const MetaTextAlignAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetTextAlign()));
+}
+
+void SvmWriter::MapModeHandler(const MetaMapModeAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeMapMode(pAction->GetMapMode());
+}
+
+void SvmWriter::FontHandler(const MetaFontAction* pAction, ImplMetaWriteData* pData)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ WriteFont(mrStream, pAction->GetFont());
+ pData->meActualCharSet = pAction->GetFont().GetCharSet();
+ if (pData->meActualCharSet == RTL_TEXTENCODING_DONTKNOW)
+ pData->meActualCharSet = osl_getThreadTextEncoding();
+}
+
+void SvmWriter::PushHandler(const MetaPushAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetFlags()));
+}
+
+void SvmWriter::PopHandler(const MetaPopAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+}
+
+void SvmWriter::RasterOpHandler(const MetaRasterOpAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetRasterOp()));
+}
+
+void SvmWriter::TransparentHandler(const MetaTransparentAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ // #i105373# The tools::PolyPolygon in this action may be a curve; this
+ // was ignored until now what is an error. To make older office
+ // versions work with MetaFiles, i opt for applying AdaptiveSubdivide
+ // to the PolyPolygon.
+ // The alternative would be to really write the curve information
+ // like in MetaPolyPolygonAction::Write (where someone extended it
+ // correctly, but not here :-( ).
+ // The golden solution would be to combine both, but i think it's
+ // not necessary; a good subdivision will be sufficient.
+ tools::PolyPolygon aNoCurvePolyPolygon;
+ pAction->GetPolyPolygon().AdaptiveSubdivide(aNoCurvePolyPolygon);
+
+ WritePolyPolygon(mrStream, aNoCurvePolyPolygon);
+ mrStream.WriteUInt16(pAction->GetTransparence());
+}
+
+void SvmWriter::FloatTransparentHandler(const MetaFloatTransparentAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ SvmWriter aWriter(mrStream);
+ GDIMetaFile aMtf = pAction->GetGDIMetaFile();
+ aWriter.Write(aMtf);
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetPoint());
+ aSerializer.writeSize(pAction->GetSize());
+ aSerializer.writeGradient(pAction->GetGradient());
+}
+
+void SvmWriter::EPSHandler(const MetaEPSAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writeGfxLink(pAction->GetLink());
+ aSerializer.writePoint(pAction->GetPoint());
+ aSerializer.writeSize(pAction->GetSize());
+
+ SvmWriter aWriter(mrStream);
+ GDIMetaFile aMtf = pAction->GetSubstitute();
+ aWriter.Write(aMtf);
+}
+
+void SvmWriter::RefPointHandler(const MetaRefPointAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+
+ TypeSerializer aSerializer(mrStream);
+ aSerializer.writePoint(pAction->GetRefPoint());
+ mrStream.WriteBool(pAction->IsSetting());
+}
+
+void SvmWriter::CommentHandler(const MetaCommentAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ write_uInt16_lenPrefixed_uInt8s_FromOString(mrStream, pAction->GetComment());
+ mrStream.WriteInt32(pAction->GetValue()).WriteUInt32(pAction->GetDataSize());
+
+ if (pAction->GetDataSize())
+ mrStream.WriteBytes(pAction->GetData(), pAction->GetDataSize());
+}
+
+void SvmWriter::LayoutModeHandler(const MetaLayoutModeAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteUInt32(static_cast<sal_uInt32>(pAction->GetLayoutMode()));
+}
+
+void SvmWriter::TextLanguageHandler(const MetaTextLanguageAction* pAction)
+{
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetType()));
+ VersionCompatWrite aCompat(mrStream, 1);
+ mrStream.WriteUInt16(static_cast<sal_uInt16>(pAction->GetTextLanguage()));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */