summaryrefslogtreecommitdiff
path: root/xmloff/source/draw/xexptran.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/draw/xexptran.cxx')
-rw-r--r--xmloff/source/draw/xexptran.cxx3120
1 files changed, 3120 insertions, 0 deletions
diff --git a/xmloff/source/draw/xexptran.cxx b/xmloff/source/draw/xexptran.cxx
new file mode 100644
index 000000000000..87830d8b1e6c
--- /dev/null
+++ b/xmloff/source/draw/xexptran.cxx
@@ -0,0 +1,3120 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_xmloff.hxx"
+#include "xexptran.hxx"
+#include <tools/debug.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <xmloff/xmluconv.hxx>
+#include <tools/gen.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/tuple/b3dtuple.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <tools/string.hxx>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+using namespace ::com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// Defines
+
+#define BORDER_INTEGERS_ARE_EQUAL (4)
+
+//////////////////////////////////////////////////////////////////////////////
+// Predeclarations
+
+void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen);
+void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection);
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// parsing help functions for simple chars
+void Imp_SkipSpaces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
+{
+ while(rPos < nLen
+ && sal_Unicode(' ') == rStr[rPos])
+ rPos++;
+}
+
+void Imp_SkipSpacesAndOpeningBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
+{
+ while(rPos < nLen
+ && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode('(') == rStr[rPos]))
+ rPos++;
+}
+
+void Imp_SkipSpacesAndCommas(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
+{
+ while(rPos < nLen
+ && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(',') == rStr[rPos]))
+ rPos++;
+}
+
+void Imp_SkipSpacesAndClosingBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
+{
+ while(rPos < nLen
+ && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(')') == rStr[rPos]))
+ rPos++;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// parsing help functions for integer numbers
+
+bool Imp_IsOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
+{
+ sal_Unicode aChar(rStr[nPos]);
+
+ if((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ || (bSignAllowed && sal_Unicode('+') == aChar)
+ || (bSignAllowed && sal_Unicode('-') == aChar)
+ )
+ return true;
+ return false;
+}
+
+bool Imp_IsOnUnitChar(const OUString& rStr, const sal_Int32 nPos)
+{
+ sal_Unicode aChar(rStr[nPos]);
+
+ if((sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
+ || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
+ || sal_Unicode('%') == aChar
+ )
+ return true;
+ return false;
+}
+
+void Imp_SkipNumber(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
+{
+ bool bSignAllowed(true);
+
+ while(rPos < nLen && Imp_IsOnNumberChar(rStr, rPos, bSignAllowed))
+ {
+ bSignAllowed = false;
+ rPos++;
+ }
+}
+
+void Imp_SkipNumberAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
+ const sal_Int32 nLen)
+{
+ Imp_SkipNumber(rStr, rPos, nLen);
+ Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
+}
+
+// #100617# Allow to skip doubles, too.
+void Imp_SkipDoubleAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
+ const sal_Int32 nLen)
+{
+ Imp_SkipDouble(rStr, rPos, nLen);
+ Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
+}
+
+void Imp_PutNumberChar(OUString& rStr, sal_Int32 nValue)
+{
+ OUStringBuffer sStringBuffer;
+ SvXMLUnitConverter::convertNumber(sStringBuffer, nValue);
+ rStr += OUString(sStringBuffer.makeStringAndClear());
+}
+
+void Imp_PutNumberCharWithSpace(OUString& rStr, sal_Int32 nValue)
+{
+ const sal_Int32 aLen(rStr.getLength());
+ if(aLen)
+ if(Imp_IsOnNumberChar(rStr, aLen - 1, false) && nValue >= 0)
+ rStr += String(sal_Unicode(' '));
+ Imp_PutNumberChar(rStr, nValue);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// parsing help functions for double numbers
+
+void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32)
+{
+ sal_Unicode aChar(rStr[rPos]);
+
+ if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
+ aChar = rStr[++rPos];
+
+ while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ || sal_Unicode('.') == aChar)
+ {
+ aChar = rStr[++rPos];
+ }
+
+ if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
+ {
+ aChar = rStr[++rPos];
+
+ if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
+ aChar = rStr[++rPos];
+
+ while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ {
+ aChar = rStr[++rPos];
+ }
+ }
+}
+
+double Imp_GetDoubleChar(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen,
+ const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false)
+{
+ sal_Unicode aChar(rStr[rPos]);
+ OUStringBuffer sNumberString;
+
+ if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
+ {
+ sNumberString.append(rStr[rPos]);
+ aChar = rStr[++rPos];
+ }
+
+ while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ || sal_Unicode('.') == aChar)
+ {
+ sNumberString.append(rStr[rPos]);
+ aChar = rStr[++rPos];
+ }
+
+ if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
+ {
+ sNumberString.append(rStr[rPos]);
+ aChar = rStr[++rPos];
+
+ if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
+ {
+ sNumberString.append(rStr[rPos]);
+ aChar = rStr[++rPos];
+ }
+
+ while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
+ {
+ sNumberString.append(rStr[rPos]);
+ aChar = rStr[++rPos];
+ }
+ }
+
+ if(bLookForUnits)
+ {
+ Imp_SkipSpaces(rStr, rPos, nLen);
+ while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos))
+ sNumberString.append(rStr[rPos++]);
+ }
+
+ if(sNumberString.getLength())
+ {
+ if(bLookForUnits)
+ rConv.convertDouble(fRetval, sNumberString.makeStringAndClear(), true);
+ else
+ rConv.convertDouble(fRetval, sNumberString.makeStringAndClear());
+ }
+
+ return fRetval;
+}
+
+void Imp_PutDoubleChar(OUString& rStr, const SvXMLUnitConverter& rConv, double fValue,
+ bool bConvertUnits = false)
+{
+ OUStringBuffer sStringBuffer;
+
+ if(bConvertUnits)
+ rConv.convertDouble(sStringBuffer, fValue, true);
+ else
+ rConv.convertDouble(sStringBuffer, fValue);
+
+ rStr += OUString(sStringBuffer.makeStringAndClear());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// base class of all 2D transform objects
+
+struct ImpSdXMLExpTransObj2DBase
+{
+ sal_uInt16 mnType;
+ ImpSdXMLExpTransObj2DBase(sal_uInt16 nType)
+ : mnType(nType) {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// possible object types for 2D
+
+#define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000
+#define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001
+#define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002
+#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003
+#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004
+#define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005
+
+//////////////////////////////////////////////////////////////////////////////
+// classes of objects, different sizes
+
+struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase
+{
+ double mfRotate;
+ ImpSdXMLExpTransObj2DRotate(double fVal)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {}
+};
+struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase
+{
+ ::basegfx::B2DTuple maScale;
+ ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {}
+};
+struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase
+{
+ ::basegfx::B2DTuple maTranslate;
+ ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {}
+};
+struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase
+{
+ double mfSkewX;
+ ImpSdXMLExpTransObj2DSkewX(double fVal)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {}
+};
+struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase
+{
+ double mfSkewY;
+ ImpSdXMLExpTransObj2DSkewY(double fVal)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {}
+};
+struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase
+{
+ ::basegfx::B2DHomMatrix maMatrix;
+ ImpSdXMLExpTransObj2DMatrix(const ::basegfx::B2DHomMatrix& rNew)
+ : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(rNew) {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// delete all entries in list
+
+void SdXMLImExTransform2D::EmptyList()
+{
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj2DBase* pObj = maList[a];
+
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
+ {
+ delete (ImpSdXMLExpTransObj2DRotate*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
+ {
+ delete (ImpSdXMLExpTransObj2DScale*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
+ {
+ delete (ImpSdXMLExpTransObj2DTranslate*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
+ {
+ delete (ImpSdXMLExpTransObj2DSkewX*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
+ {
+ delete (ImpSdXMLExpTransObj2DSkewY*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
+ {
+ delete (ImpSdXMLExpTransObj2DMatrix*)pObj;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
+ break;
+ }
+ }
+ }
+
+ maList.clear();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// add members
+
+void SdXMLImExTransform2D::AddRotate(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DRotate(fNew));
+}
+
+void SdXMLImExTransform2D::AddScale(const ::basegfx::B2DTuple& rNew)
+{
+ if(1.0 != rNew.getX() || 1.0 != rNew.getY())
+ maList.push_back(new ImpSdXMLExpTransObj2DScale(rNew));
+}
+
+void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew)
+{
+ if(!rNew.equalZero())
+ maList.push_back(new ImpSdXMLExpTransObj2DTranslate(rNew));
+}
+
+void SdXMLImExTransform2D::AddSkewX(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fNew));
+}
+
+void SdXMLImExTransform2D::AddSkewY(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fNew));
+}
+
+void SdXMLImExTransform2D::AddMatrix(const ::basegfx::B2DHomMatrix& rNew)
+{
+ if(!rNew.isIdentity())
+ maList.push_back(new ImpSdXMLExpTransObj2DMatrix(rNew));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// gen string for export
+const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv)
+{
+ OUString aNewString;
+ OUString aClosingBrace(sal_Unicode(')'));
+ OUString aEmptySpace(sal_Unicode(' '));
+
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj2DBase* pObj = maList[a];
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "rotate (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "scale (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getX());
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getY());
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "translate (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getX(), true);
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getY(), true);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "skewX (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "skewY (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "matrix (" ));
+
+ // a
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 0));
+ aNewString += aEmptySpace;
+
+ // b
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 0));
+ aNewString += aEmptySpace;
+
+ // c
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 1));
+ aNewString += aEmptySpace;
+
+ // d
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 1));
+ aNewString += aEmptySpace;
+
+ // e
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 2), true);
+ aNewString += aEmptySpace;
+
+ // f
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 2), true);
+
+ aNewString += aClosingBrace;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
+ break;
+ }
+ }
+
+ // if not the last entry, add one space to next tag
+ if(a + 1UL != maList.size())
+ {
+ aNewString += aEmptySpace;
+ }
+ }
+
+ // fill string form OUString
+ msString = aNewString;
+
+ return msString;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// for Import: constructor with string, parses it and generates entries
+SdXMLImExTransform2D::SdXMLImExTransform2D(const OUString& rNew, const SvXMLUnitConverter& rConv)
+{
+ SetString(rNew, rConv);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// sets new string, parses it and generates entries
+void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
+{
+ msString = rNew;
+ EmptyList();
+
+ if(msString.getLength())
+ {
+ const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
+ const sal_Int32 nLen(aStr.getLength());
+
+ const OUString aString_rotate(RTL_CONSTASCII_USTRINGPARAM( "rotate" ));
+ const OUString aString_scale(RTL_CONSTASCII_USTRINGPARAM( "scale" ));
+ const OUString aString_translate(RTL_CONSTASCII_USTRINGPARAM( "translate" ));
+ const OUString aString_skewX(RTL_CONSTASCII_USTRINGPARAM( "skewX" ));
+ const OUString aString_skewY(RTL_CONSTASCII_USTRINGPARAM( "skewY" ));
+ const OUString aString_matrix(RTL_CONSTASCII_USTRINGPARAM( "matrix" ));
+
+ sal_Int32 nPos(0);
+
+ while(nPos < nLen)
+ {
+ // skip spaces
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // look for tag
+ if(nPos < nLen)
+ {
+ if(nPos == aStr.indexOf(aString_rotate, nPos))
+ {
+ double fValue(0.0);
+ nPos += 6;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DRotate(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_scale, nPos))
+ {
+ ::basegfx::B2DTuple aValue(1.0, 1.0);
+ nPos += 5;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
+
+ if(aValue.getX() != 1.0 || aValue.getY() != 1.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DScale(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_translate, nPos))
+ {
+ ::basegfx::B2DTuple aValue;
+ nPos += 9;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
+
+ if(!aValue.equalZero())
+ maList.push_back(new ImpSdXMLExpTransObj2DTranslate(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_skewX, nPos))
+ {
+ double fValue(0.0);
+ nPos += 5;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_skewY, nPos))
+ {
+ double fValue(0.0);
+ nPos += 5;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_matrix, nPos))
+ {
+ ::basegfx::B2DHomMatrix aValue;
+
+ nPos += 6;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+
+ // a
+ aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // b
+ aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // c
+ aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // d
+ aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // e
+ aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // f
+ aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ if(!aValue.isIdentity())
+ maList.push_back(new ImpSdXMLExpTransObj2DMatrix(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else
+ {
+ nPos++;
+ }
+ }
+ }
+ }
+}
+
+void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans)
+{
+ rFullTrans.identity();
+
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj2DBase* pObj = maList[a];
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
+ {
+ // #i78696#
+ // mfRotate is mathematically wrong oriented since we export/import the angle
+ // values mirrored. This error is fixed in the API, but not yet in the FileFormat.
+ // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next
+ // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary
+ // to mirror the value here
+ rFullTrans.rotate(((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate * -1.0);
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
+ {
+ const ::basegfx::B2DTuple& rScale = ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale;
+ rFullTrans.scale(rScale.getX(), rScale.getY());
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
+ {
+ const ::basegfx::B2DTuple& rTranslate = ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate;
+ rFullTrans.translate(rTranslate.getX(), rTranslate.getY());
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
+ {
+ rFullTrans.shearX(tan(((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX));
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
+ {
+ rFullTrans.shearY(tan(((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY));
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
+ {
+ rFullTrans *= ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
+ break;
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// base class of all 3D transform objects
+
+struct ImpSdXMLExpTransObj3DBase
+{
+ sal_uInt16 mnType;
+ ImpSdXMLExpTransObj3DBase(sal_uInt16 nType)
+ : mnType(nType) {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// possible object types for 3D
+
+#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000
+#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001
+#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002
+#define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003
+#define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004
+#define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005
+
+//////////////////////////////////////////////////////////////////////////////
+// classes of objects, different sizes
+
+struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase
+{
+ double mfRotateX;
+ ImpSdXMLExpTransObj3DRotateX(double fVal)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {}
+};
+struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase
+{
+ double mfRotateY;
+ ImpSdXMLExpTransObj3DRotateY(double fVal)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {}
+};
+struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase
+{
+ double mfRotateZ;
+ ImpSdXMLExpTransObj3DRotateZ(double fVal)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {}
+};
+struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase
+{
+ ::basegfx::B3DTuple maScale;
+ ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {}
+};
+struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase
+{
+ ::basegfx::B3DTuple maTranslate;
+ ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {}
+};
+struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase
+{
+ ::basegfx::B3DHomMatrix maMatrix;
+ ImpSdXMLExpTransObj3DMatrix(const ::basegfx::B3DHomMatrix& rNew)
+ : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(rNew) {}
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// delete all entries in list
+
+void SdXMLImExTransform3D::EmptyList()
+{
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj3DBase* pObj = maList[a];
+
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
+ {
+ delete (ImpSdXMLExpTransObj3DRotateX*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
+ {
+ delete (ImpSdXMLExpTransObj3DRotateY*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
+ {
+ delete (ImpSdXMLExpTransObj3DRotateZ*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
+ {
+ delete (ImpSdXMLExpTransObj3DScale*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
+ {
+ delete (ImpSdXMLExpTransObj3DTranslate*)pObj;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
+ {
+ delete (ImpSdXMLExpTransObj3DMatrix*)pObj;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
+ break;
+ }
+ }
+ }
+
+ maList.clear();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// add members
+
+void SdXMLImExTransform3D::AddRotateX(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fNew));
+}
+
+void SdXMLImExTransform3D::AddRotateY(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fNew));
+}
+
+void SdXMLImExTransform3D::AddRotateZ(double fNew)
+{
+ if(fNew != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fNew));
+}
+
+void SdXMLImExTransform3D::AddScale(const ::basegfx::B3DTuple& rNew)
+{
+ if(1.0 != rNew.getX() || 1.0 != rNew.getY() || 1.0 != rNew.getZ())
+ maList.push_back(new ImpSdXMLExpTransObj3DScale(rNew));
+}
+
+void SdXMLImExTransform3D::AddTranslate(const ::basegfx::B3DTuple& rNew)
+{
+ if(!rNew.equalZero())
+ maList.push_back(new ImpSdXMLExpTransObj3DTranslate(rNew));
+}
+
+void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew)
+{
+ if(!rNew.isIdentity())
+ maList.push_back(new ImpSdXMLExpTransObj3DMatrix(rNew));
+}
+
+void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat)
+{
+ ::basegfx::B3DHomMatrix aExportMatrix;
+
+ aExportMatrix.set(0, 0, xHomMat.Line1.Column1);
+ aExportMatrix.set(0, 1, xHomMat.Line1.Column2);
+ aExportMatrix.set(0, 2, xHomMat.Line1.Column3);
+ aExportMatrix.set(0, 3, xHomMat.Line1.Column4);
+ aExportMatrix.set(1, 0, xHomMat.Line2.Column1);
+ aExportMatrix.set(1, 1, xHomMat.Line2.Column2);
+ aExportMatrix.set(1, 2, xHomMat.Line2.Column3);
+ aExportMatrix.set(1, 3, xHomMat.Line2.Column4);
+ aExportMatrix.set(2, 0, xHomMat.Line3.Column1);
+ aExportMatrix.set(2, 1, xHomMat.Line3.Column2);
+ aExportMatrix.set(2, 2, xHomMat.Line3.Column3);
+ aExportMatrix.set(2, 3, xHomMat.Line3.Column4);
+
+ AddMatrix(aExportMatrix);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// gen string for export
+const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv)
+{
+ OUString aNewString;
+ OUString aClosingBrace(sal_Unicode(')'));
+ OUString aEmptySpace(sal_Unicode(' '));
+
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj3DBase* pObj = maList[a];
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "rotatex (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "rotatey (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "rotatez (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "scale (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getX());
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getY());
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getZ());
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "translate (" ));
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getX(), true);
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getY(), true);
+ aNewString += aEmptySpace;
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getZ(), true);
+ aNewString += aClosingBrace;
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
+ {
+ aNewString += OUString(RTL_CONSTASCII_USTRINGPARAM( "matrix (" ));
+
+ // a
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 0));
+ aNewString += aEmptySpace;
+
+ // b
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 0));
+ aNewString += aEmptySpace;
+
+ // c
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 0));
+ aNewString += aEmptySpace;
+
+ // d
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 1));
+ aNewString += aEmptySpace;
+
+ // e
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 1));
+ aNewString += aEmptySpace;
+
+ // f
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 1));
+ aNewString += aEmptySpace;
+
+ // g
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 2));
+ aNewString += aEmptySpace;
+
+ // h
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 2));
+ aNewString += aEmptySpace;
+
+ // i
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 2));
+ aNewString += aEmptySpace;
+
+ // j
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 3), true);
+ aNewString += aEmptySpace;
+
+ // k
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 3), true);
+ aNewString += aEmptySpace;
+
+ // l
+ Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 3), true);
+
+ aNewString += aClosingBrace;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
+ break;
+ }
+ }
+
+ // if not the last entry, add one space to next tag
+ if(a + 1UL != maList.size())
+ {
+ aNewString += aEmptySpace;
+ }
+ }
+
+ // fill string form OUString
+ msString = aNewString;
+
+ return msString;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// for Import: constructor with string, parses it and generates entries
+SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv)
+{
+ SetString(rNew, rConv);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// sets new string, parses it and generates entries
+void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
+{
+ msString = rNew;
+ EmptyList();
+
+ if(msString.getLength())
+ {
+ const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
+ const sal_Int32 nLen(aStr.getLength());
+
+ const OUString aString_rotatex(RTL_CONSTASCII_USTRINGPARAM( "rotatex" ));
+ const OUString aString_rotatey(RTL_CONSTASCII_USTRINGPARAM( "rotatey" ));
+ const OUString aString_rotatez(RTL_CONSTASCII_USTRINGPARAM( "rotatez" ));
+ const OUString aString_scale(RTL_CONSTASCII_USTRINGPARAM( "scale" ));
+ const OUString aString_translate(RTL_CONSTASCII_USTRINGPARAM( "translate" ));
+ const OUString aString_matrix(RTL_CONSTASCII_USTRINGPARAM( "matrix" ));
+
+ sal_Int32 nPos(0);
+
+ while(nPos < nLen)
+ {
+ // skip spaces
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // look for tag
+ if(nPos < nLen)
+ {
+ if(nPos == aStr.indexOf(aString_rotatex, nPos))
+ {
+ double fValue(0.0);
+
+ nPos += 7;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_rotatey, nPos))
+ {
+ double fValue(0.0);
+
+ nPos += 7;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_rotatez, nPos))
+ {
+ double fValue(0.0);
+
+ nPos += 7;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
+ if(fValue != 0.0)
+ maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_scale, nPos))
+ {
+ ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0);
+
+ nPos += 5;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ()));
+
+ if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ())
+ maList.push_back(new ImpSdXMLExpTransObj3DScale(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_translate, nPos))
+ {
+ ::basegfx::B3DTuple aValue;
+
+ nPos += 9;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+ aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+ aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true));
+
+ if(!aValue.equalZero())
+ maList.push_back(new ImpSdXMLExpTransObj3DTranslate(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else if(nPos == aStr.indexOf(aString_matrix, nPos))
+ {
+ ::basegfx::B3DHomMatrix aValue;
+
+ nPos += 6;
+ Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
+
+ // a
+ aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // b
+ aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // c
+ aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // d
+ aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // e
+ aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // f
+ aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // g
+ aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // h
+ aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // i
+ aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2)));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // j
+ aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // k
+ aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // l
+ aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true));
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ if(!aValue.isIdentity())
+ maList.push_back(new ImpSdXMLExpTransObj3DMatrix(aValue));
+
+ Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
+ }
+ else
+ {
+ nPos++;
+ }
+ }
+ }
+ }
+}
+
+bool SdXMLImExTransform3D::GetFullHomogenTransform(com::sun::star::drawing::HomogenMatrix& xHomMat)
+{
+ ::basegfx::B3DHomMatrix aFullTransform;
+ GetFullTransform(aFullTransform);
+
+ if(!aFullTransform.isIdentity())
+ {
+ xHomMat.Line1.Column1 = aFullTransform.get(0, 0);
+ xHomMat.Line1.Column2 = aFullTransform.get(0, 1);
+ xHomMat.Line1.Column3 = aFullTransform.get(0, 2);
+ xHomMat.Line1.Column4 = aFullTransform.get(0, 3);
+
+ xHomMat.Line2.Column1 = aFullTransform.get(1, 0);
+ xHomMat.Line2.Column2 = aFullTransform.get(1, 1);
+ xHomMat.Line2.Column3 = aFullTransform.get(1, 2);
+ xHomMat.Line2.Column4 = aFullTransform.get(1, 3);
+
+ xHomMat.Line3.Column1 = aFullTransform.get(2, 0);
+ xHomMat.Line3.Column2 = aFullTransform.get(2, 1);
+ xHomMat.Line3.Column3 = aFullTransform.get(2, 2);
+ xHomMat.Line3.Column4 = aFullTransform.get(2, 3);
+
+ xHomMat.Line4.Column1 = aFullTransform.get(3, 0);
+ xHomMat.Line4.Column2 = aFullTransform.get(3, 1);
+ xHomMat.Line4.Column3 = aFullTransform.get(3, 2);
+ xHomMat.Line4.Column4 = aFullTransform.get(3, 3);
+
+ return true;
+ }
+
+ return false;
+}
+
+void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans)
+{
+ rFullTrans.identity();
+
+ const sal_uInt32 nCount = maList.size();
+ for(sal_uInt32 a(0L); a < nCount; a++)
+ {
+ ImpSdXMLExpTransObj3DBase* pObj = maList[a];
+ switch(pObj->mnType)
+ {
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
+ {
+ rFullTrans.rotate(((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX, 0.0, 0.0);
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
+ {
+ rFullTrans.rotate(0.0, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY, 0.0);
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
+ {
+ rFullTrans.rotate(0.0, 0.0, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
+ {
+ const ::basegfx::B3DTuple& rScale = ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale;
+ rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ());
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
+ {
+ const ::basegfx::B3DTuple& rTranslate = ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate;
+ rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
+ break;
+ }
+ case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
+ {
+ rFullTrans *= ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix;
+ break;
+ }
+ default :
+ {
+ DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
+ break;
+ }
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX, sal_Int32 nY, sal_Int32 nW, sal_Int32 nH)
+: mnX( nX ),
+ mnY( nY ),
+ mnW( nW ),
+ mnH( nH )
+{
+}
+
+// #100617# Asked vincent hardy: svg:viewBox values may be double precision.
+SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv)
+: msString(rNew),
+ mnX( 0L ),
+ mnY( 0L ),
+ mnW( 1000L ),
+ mnH( 1000L )
+{
+ if(msString.getLength())
+ {
+ const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
+ const sal_Int32 nLen(aStr.getLength());
+ sal_Int32 nPos(0);
+
+ // skip starting spaces
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // get mX, #100617# be prepared for doubles
+ mnX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnX));
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // get mY, #100617# be prepared for doubles
+ mnY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnY));
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // get mW, #100617# be prepared for doubles
+ mnW = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnW));
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // get mH, #100617# be prepared for doubles
+ mnH = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnH));
+ }
+}
+
+const OUString& SdXMLImExViewBox::GetExportString()
+{
+ OUString aNewString;
+ OUString aEmptySpace(sal_Unicode(' '));
+
+ Imp_PutNumberChar(aNewString, mnX);
+ aNewString += aEmptySpace;
+
+ Imp_PutNumberChar(aNewString, mnY);
+ aNewString += aEmptySpace;
+
+ Imp_PutNumberChar(aNewString, mnW);
+ aNewString += aEmptySpace;
+
+ Imp_PutNumberChar(aNewString, mnH);
+
+ // set new string
+ msString = aNewString;
+
+ return msString;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence* pPoints,
+ const SdXMLImExViewBox& rViewBox,
+ const awt::Point& rObjectPos,
+ const awt::Size& rObjectSize,
+ // #96328#
+ const bool bClosed)
+: maPoly( 0L )
+{
+ DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExPointsElement(!)");
+
+ // add polygon to string
+ sal_Int32 nCnt(pPoints->getLength());
+
+ // #104076# Convert to string only when at last one point included
+ if(nCnt > 0)
+ {
+ OUString aNewString;
+ awt::Point* pArray = pPoints->getArray();
+
+ // last point same? Ignore it.
+ // #96328# ...but only when polygon is CLOSED
+ if(bClosed && (pArray->X == (pArray + (nCnt - 1))->X) && (pArray->Y == (pArray + (nCnt - 1))->Y))
+ nCnt--;
+
+ // object size and ViewBox size different?
+ bool bScale(rObjectSize.Width != rViewBox.GetWidth()
+ || rObjectSize.Height != rViewBox.GetHeight());
+ bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
+
+ for(sal_Int32 a(0L); a < nCnt; a++)
+ {
+ // prepare coordinates
+ sal_Int32 nX( pArray->X - rObjectPos.X );
+ sal_Int32 nY( pArray->Y - rObjectPos.Y );
+
+ if(bScale && rObjectSize.Width && rObjectSize.Height)
+ {
+ nX = (nX * rViewBox.GetWidth()) / rObjectSize.Width;
+ nY = (nY * rViewBox.GetHeight()) / rObjectSize.Height;
+ }
+
+ if(bTranslate)
+ {
+ nX += rViewBox.GetX();
+ nY += rViewBox.GetY();
+ }
+
+ // X and comma
+ Imp_PutNumberChar(aNewString, nX);
+ aNewString += String(sal_Unicode(','));
+
+ // Y and space (not for last)
+ Imp_PutNumberChar(aNewString, nY);
+ if(a + 1 != nCnt)
+ aNewString += String(sal_Unicode(' '));
+
+ // next point
+ pArray++;
+ }
+
+ // set new string
+ msString = aNewString;
+ }
+}
+
+// #100617# svg:polyline or svg:polygon values may be double precision.
+SdXMLImExPointsElement::SdXMLImExPointsElement(const OUString& rNew,
+ const SdXMLImExViewBox& rViewBox,
+ const awt::Point& rObjectPos,
+ const awt::Size& rObjectSize,
+ const SvXMLUnitConverter& rConv)
+: msString( rNew ),
+ maPoly( 0L )
+{
+ // convert string to polygon
+ const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
+ const sal_Int32 nLen(aStr.getLength());
+ sal_Int32 nPos(0);
+ sal_Int32 nNumPoints(0L);
+
+ // skip starting spaces
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // count points in first loop
+ while(nPos < nLen)
+ {
+ // skip number, #100617# be prepared for doubles
+ Imp_SkipDouble(aStr, nPos, nLen);
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // skip number, #100617# be prepared for doubles
+ Imp_SkipDouble(aStr, nPos, nLen);
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // one more point
+ nNumPoints++;
+ }
+
+ // second loop
+ if(nNumPoints)
+ {
+ nPos = 0L;
+ maPoly.realloc(1L);
+ drawing::PointSequence* pOuterSequence = maPoly.getArray();
+ pOuterSequence->realloc(nNumPoints);
+ awt::Point* pInnerSequence = pOuterSequence->getArray();
+
+ // object size and ViewBox size different?
+ bool bScale(rObjectSize.Width != rViewBox.GetWidth()
+ || rObjectSize.Height != rViewBox.GetHeight());
+ bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
+
+ // skip starting spaces
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen)
+ {
+ // prepare new parameter pair
+ sal_Int32 nX(0L);
+ sal_Int32 nY(0L);
+
+ // get mX, #100617# be prepared for doubles
+ nX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nX));
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // get mY, #100617# be prepared for doubles
+ nY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nY));
+
+ // skip spaces and commas
+ Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
+
+ // prepare parameters
+ if(bTranslate)
+ {
+ nX -= rViewBox.GetX();
+ nY -= rViewBox.GetY();
+ }
+
+ if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight() )
+ {
+ nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
+ nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
+ }
+
+ nX += rObjectPos.X;
+ nY += rObjectPos.Y;
+
+ // add new point
+ *pInnerSequence = awt::Point( nX, nY );
+ pInnerSequence++;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox)
+: mrViewBox( rViewBox ),
+ mbIsClosed( false ),
+ mbIsCurve( false ),
+ mnLastX( 0L ),
+ mnLastY( 0L ),
+ maPoly( 0L ),
+ maFlag( 0L )
+{
+}
+
+void Imp_GetPrevPos(awt::Point*& pPrevPos1,
+ drawing::PolygonFlags& aPrevFlag1,
+ const bool bClosed, awt::Point* pPoints,
+ drawing::PolygonFlags* pFlags, const sal_Int32 nPos,
+ const sal_Int32 nCnt, const sal_Int32 nAdd)
+{
+ if(bClosed)
+ {
+ pPrevPos1 = pPoints + ((nPos + nCnt - nAdd) % nCnt);
+ aPrevFlag1 = *(pFlags + ((nPos + nCnt - nAdd) % nCnt));
+ }
+ else if(nPos > (nAdd - 1))
+ {
+ pPrevPos1 = pPoints + (nPos - nAdd);
+ aPrevFlag1 = *(pFlags + (nPos - nAdd));
+ }
+ else
+ pPrevPos1 = 0L;
+}
+
+void Imp_PrepareCoorExport(sal_Int32& nX, sal_Int32& nY,
+ const awt::Point* pPointArray, const awt::Point& rObjectPos,
+ const awt::Size& rObjectSize, const SdXMLImExViewBox& mrViewBox,
+ const bool bScale, const bool bTranslate)
+{
+ nX = pPointArray->X - rObjectPos.X;
+ nY = pPointArray->Y - rObjectPos.Y;
+
+ if(bScale && rObjectSize.Width && rObjectSize.Height )
+ {
+ nX = (nX * mrViewBox.GetWidth()) / rObjectSize.Width;
+ nY = (nY * mrViewBox.GetHeight()) / rObjectSize.Height;
+ }
+
+ if(bTranslate)
+ {
+ nX += mrViewBox.GetX();
+ nY += mrViewBox.GetY();
+ }
+}
+
+//#define TEST_QUADRATIC_CURVES
+#ifdef TEST_QUADRATIC_CURVES
+// To be able to test quadratic curve code: The code concerning to
+// bDoTestHere can be used (see below). Construct shapes which have their control
+// points on equal coordinates. When these are written, they can be
+// forced to create correct 'Q' and 'T' statements using this flag.
+// These may then be tested for import/exporting.
+static bool bDoTestHere(true);
+#endif // TEST_QUADRATIC_CURVES
+
+void SdXMLImExSvgDElement::AddPolygon(
+ drawing::PointSequence* pPoints,
+ drawing::FlagSequence* pFlags,
+ const awt::Point& rObjectPos,
+ const awt::Size& rObjectSize,
+ bool bClosed, bool bRelative)
+{
+ DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExSvgDElement(!)");
+
+ sal_Int32 nCnt(pPoints->getLength());
+
+ // #104076# Convert to string only when at last one point included
+ if(nCnt > 0)
+ {
+ // append polygon to string
+ OUString aNewString;
+ sal_Unicode aLastCommand = ' ';
+ awt::Point* pPointArray = pPoints->getArray();
+
+ // are the flags used at all? If not forget about them
+ if(pFlags)
+ {
+ sal_Int32 nFlagCnt(pFlags->getLength());
+
+ if(nFlagCnt)
+ {
+ bool bFlagsUsed(false);
+ drawing::PolygonFlags* pFlagArray = pFlags->getArray();
+
+ for(sal_Int32 a(0); !bFlagsUsed && a < nFlagCnt; a++)
+ if(drawing::PolygonFlags_NORMAL != *pFlagArray++)
+ bFlagsUsed = true;
+
+ if(!bFlagsUsed)
+ pFlags = 0L;
+ }
+ else
+ {
+ pFlags = 0L;
+ }
+ }
+
+ // object size and ViewBox size different?
+ bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
+ || rObjectSize.Height != mrViewBox.GetHeight());
+ bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
+
+ // #87202# rework of point reduction:
+ // Test for Last point same -> closed, ignore last point. Take
+ // some more circumstances in account when looking at curve segments.
+ drawing::PolygonFlags* pFlagArray = (pFlags) ? pFlags->getArray() : 0L;
+ if((pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y))
+ {
+ if(pFlags)
+ {
+ // point needs to be ignored if point before it is
+ // NO control point. Else the last point is needed
+ // for exporting the last segment of the curve. That means
+ // that the last and the first point will be saved double,
+ // but SVG does not support a better solution here.
+ if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2)))
+ {
+ nCnt--;
+ }
+ }
+ else
+ {
+ // no curve, ignore last point
+ nCnt--;
+ }
+ }
+
+ // bezier poly, handle curves
+ bool bDidWriteStart(false);
+
+ for(sal_Int32 a(0L); a < nCnt; a++)
+ {
+ if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray)
+ {
+ bool bDidWriteAsCurve(false);
+
+ if(bDidWriteStart)
+ {
+ if(pFlags)
+ {
+ // real curve point, get previous to see if it's a control point
+ awt::Point* pPrevPos1;
+ drawing::PolygonFlags aPrevFlag1;
+
+ Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 1);
+
+ if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1)
+ {
+ // get previous2 to see if it's a control point, too
+ awt::Point* pPrevPos2;
+ drawing::PolygonFlags aPrevFlag2;
+
+ Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 2);
+
+ if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2)
+ {
+ // get previous3 to see if it's a curve point and if,
+ // if it is fully symmetric or not
+ awt::Point* pPrevPos3;
+ drawing::PolygonFlags aPrevFlag3;
+
+ Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 3);
+
+ if(pPrevPos3)
+ {
+ // prepare coordinates
+ sal_Int32 nX, nY;
+
+ Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ // #100617# test if this curve segment may be written as
+ // a quadratic bezier
+ // That's the case if both control points are in the same place
+ // when they are prolonged to the common quadratic control point
+ // Left: P = (3P1 - P0) / 2
+ // Right: P = (3P2 - P3) / 2
+ bool bIsQuadratic(false);
+ const bool bEnableSaveQuadratic(false);
+
+ sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0));
+ sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0));
+ sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0));
+ sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0));
+ sal_Int32 nDist(0);
+
+ if(nPX_L != nPX_R)
+ {
+ nDist += abs(nPX_L - nPX_R);
+ }
+
+ if(nPY_L != nPY_R)
+ {
+ nDist += abs(nPY_L - nPY_R);
+ }
+
+ if(nDist <= BORDER_INTEGERS_ARE_EQUAL)
+ {
+ if(bEnableSaveQuadratic)
+ {
+ bIsQuadratic = true;
+ }
+ }
+
+#ifdef TEST_QUADRATIC_CURVES
+ if(bDoTestHere)
+ {
+ bIsQuadratic = false;
+
+ if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y)
+ bIsQuadratic = true;
+ }
+#endif // TEST_QUADRATIC_CURVES
+
+ if(bIsQuadratic)
+ {
+#ifdef TEST_QUADRATIC_CURVES
+ if(bDoTestHere)
+ {
+ bool bPrevPointIsSymmetric(false);
+
+ if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
+ {
+ // get previous4 to see if it's a control point
+ awt::Point* pPrevPos4;
+ drawing::PolygonFlags aPrevFlag4;
+
+ Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 4);
+
+ if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
+ {
+ // okay, prevPos3 is symmetric (c2) and prevPos4
+ // is existing control point, the 's' statement can be used
+ bPrevPointIsSymmetric = true;
+ }
+ }
+
+ if(bPrevPointIsSymmetric)
+ {
+ // write a shorthand/smooth quadratic curveto entry (T)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('t'))
+ aNewString += OUString(sal_Unicode('t'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('t');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('T'))
+ aNewString += OUString(sal_Unicode('T'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('T');
+ }
+ }
+ else
+ {
+ // prepare coordinates
+ sal_Int32 nX1, nY1;
+
+ Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ // write a quadratic curveto entry (Q)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('q'))
+ aNewString += OUString(sal_Unicode('q'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('q');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('Q'))
+ aNewString += OUString(sal_Unicode('Q'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1);
+ Imp_PutNumberCharWithSpace(aNewString, nY1);
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('Q');
+ }
+ }
+ }
+ else
+ {
+#endif // TEST_QUADRATIC_CURVES
+ awt::Point aNewPoint(nPX_L, nPY_L);
+ bool bPrevPointIsSmooth(false);
+
+ if(drawing::PolygonFlags_SMOOTH == aPrevFlag3)
+ {
+ // get previous4 to see if it's a control point
+ awt::Point* pPrevPos4;
+ drawing::PolygonFlags aPrevFlag4;
+
+ Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 4);
+
+ if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
+ {
+ // okay, prevPos3 is smooth (c1) and prevPos4
+ // is existing control point. Test if it's even symmetric
+ // and thus the 'T' statement may be used.
+ ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y);
+ ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y);
+ bool bSameLength(false);
+ bool bSameDirection(false);
+
+ // get vector values
+ Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
+
+ if(bSameLength && bSameDirection)
+ bPrevPointIsSmooth = true;
+ }
+ }
+
+ if(bPrevPointIsSmooth)
+ {
+ // write a shorthand/smooth quadratic curveto entry (T)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('t'))
+ aNewString += String(sal_Unicode('t'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('t');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('T'))
+ aNewString += String(sal_Unicode('T'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('T');
+ }
+ }
+ else
+ {
+ // prepare coordinates
+ sal_Int32 nX1, nY1;
+
+ Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ // write a quadratic curveto entry (Q)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('q'))
+ aNewString += String(sal_Unicode('q'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('q');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('Q'))
+ aNewString += String(sal_Unicode('Q'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1);
+ Imp_PutNumberCharWithSpace(aNewString, nY1);
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('Q');
+ }
+ }
+#ifdef TEST_QUADRATIC_CURVES
+ }
+#endif // TEST_QUADRATIC_CURVES
+ }
+ else
+ {
+ bool bPrevPointIsSymmetric(false);
+
+ if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
+ {
+ // get previous4 to see if it's a control point
+ awt::Point* pPrevPos4;
+ drawing::PolygonFlags aPrevFlag4;
+
+ Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
+ pFlags->getArray(), a, nCnt, 4);
+
+ if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
+ {
+ // okay, prevPos3 is symmetric (c2) and prevPos4
+ // is existing control point, the 's' statement can be used
+ bPrevPointIsSymmetric = true;
+ }
+ }
+
+ // prepare coordinates
+ sal_Int32 nX2, nY2;
+
+ Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ if(bPrevPointIsSymmetric)
+ {
+ // write a shorthand/smooth curveto entry (S)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('s'))
+ aNewString += String(sal_Unicode('s'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('s');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('S'))
+ aNewString += String(sal_Unicode('S'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX2);
+ Imp_PutNumberCharWithSpace(aNewString, nY2);
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('S');
+ }
+ }
+ else
+ {
+ // prepare coordinates
+ sal_Int32 nX1, nY1;
+
+ Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ // write a curveto entry (C)
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('c'))
+ aNewString += String(sal_Unicode('c'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
+ Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('c');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('C'))
+ aNewString += String(sal_Unicode('C'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX1);
+ Imp_PutNumberCharWithSpace(aNewString, nY1);
+ Imp_PutNumberCharWithSpace(aNewString, nX2);
+ Imp_PutNumberCharWithSpace(aNewString, nY2);
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('C');
+ }
+ }
+ }
+
+ // remember that current point IS written
+ bDidWriteAsCurve = true;
+
+ // remember new last position
+ mnLastX = nX;
+ mnLastY = nY;
+ }
+ }
+ }
+ }
+ }
+
+ if(!bDidWriteAsCurve)
+ {
+ // current point not yet written, prepare coordinates
+ sal_Int32 nX, nY;
+
+ Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
+ mrViewBox, bScale, bTranslate);
+
+ if(bDidWriteStart)
+ {
+ // write as normal point
+ if(mnLastX == nX)
+ {
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('v'))
+ aNewString += String(sal_Unicode('v'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('v');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('V'))
+ aNewString += String(sal_Unicode('V'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('V');
+ }
+ }
+ else if(mnLastY == nY)
+ {
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('h'))
+ aNewString += String(sal_Unicode('h'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+
+ aLastCommand = sal_Unicode('h');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('H'))
+ aNewString += String(sal_Unicode('H'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+
+ aLastCommand = sal_Unicode('H');
+ }
+ }
+ else
+ {
+ if(bRelative)
+ {
+ if(aLastCommand != sal_Unicode('l'))
+ aNewString += String(sal_Unicode('l'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('l');
+ }
+ else
+ {
+ if(aLastCommand != sal_Unicode('L'))
+ aNewString += String(sal_Unicode('L'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('L');
+ }
+ }
+ }
+ else
+ {
+ // write as start point
+ if(bRelative)
+ {
+ aNewString += String(sal_Unicode('m'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
+ Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
+
+ aLastCommand = sal_Unicode('l');
+ }
+ else
+ {
+ aNewString += String(sal_Unicode('M'));
+
+ Imp_PutNumberCharWithSpace(aNewString, nX);
+ Imp_PutNumberCharWithSpace(aNewString, nY);
+
+ aLastCommand = sal_Unicode('L');
+ }
+
+ // remember start written
+ bDidWriteStart = true;
+ }
+
+ // remember new last position
+ mnLastX = nX;
+ mnLastY = nY;
+ }
+ }
+
+ // next point
+ pPointArray++;
+ pFlagArray++;
+ }
+
+ // close path if closed poly
+ if(bClosed)
+ {
+ if(bRelative)
+ aNewString += String(sal_Unicode('z'));
+ else
+ aNewString += String(sal_Unicode('Z'));
+ }
+
+ // append new string
+ msString += aNewString;
+ }
+}
+
+// #100617# Linear double reader
+double Imp_ImportDoubleAndSpaces(
+ double fRetval, const OUString& rStr, sal_Int32& rPos,
+ const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
+{
+ fRetval = Imp_GetDoubleChar(rStr, rPos, nLen, rConv, fRetval);
+ Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
+ return fRetval;
+}
+
+// #100617# Allow to read doubles, too. This will need to be changed to
+// the usage of Imp_ImportDoubleAndSpaces(...). For now, this is sufficient
+// since the interface cannot transport doubles.
+sal_Int32 Imp_ImportNumberAndSpaces(
+ sal_Int32 nRetval, const OUString& rStr, sal_Int32& rPos,
+ const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
+{
+ nRetval = FRound(Imp_ImportDoubleAndSpaces(double(nRetval), rStr, rPos, nLen, rConv));
+ Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
+ return nRetval;
+}
+
+void Imp_PrepareCoorImport(sal_Int32& nX, sal_Int32& nY,
+ const awt::Point& rObjectPos, const awt::Size& rObjectSize,
+ const SdXMLImExViewBox& rViewBox, const bool bScale, const bool bTranslate)
+{
+ if(bTranslate)
+ {
+ nX -= rViewBox.GetX();
+ nY -= rViewBox.GetY();
+ }
+
+ if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight())
+ {
+ nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
+ nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
+ }
+
+ nX += rObjectPos.X;
+ nY += rObjectPos.Y;
+}
+
+void Imp_AddExportPoints(sal_Int32 nX, sal_Int32 nY,
+ awt::Point* pPoints, drawing::PolygonFlags* pFlags,
+ const sal_Int32 nInnerIndex,
+ drawing::PolygonFlags eFlag)
+{
+ if(pPoints)
+ pPoints[nInnerIndex] = awt::Point( nX, nY );
+
+ if(pFlags)
+ pFlags[nInnerIndex] = eFlag;
+}
+
+void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection)
+{
+ const sal_Int32 nLen1(FRound(aVec1.getLength()));
+ const sal_Int32 nLen2(FRound(aVec2.getLength()));
+ aVec1.normalize();
+ aVec2.normalize();
+ aVec1 += aVec2;
+ const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0)));
+
+ bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL);
+ bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL);
+}
+
+void Imp_CorrectPolygonFlag(const sal_uInt32 nInnerIndex, const awt::Point* const pInnerSequence,
+ drawing::PolygonFlags* const pInnerFlags, const sal_Int32 nX1, const sal_Int32 nY1)
+{
+ if(nInnerIndex)
+ {
+ const awt::Point aPPrev1 = pInnerSequence[nInnerIndex - 1];
+
+ if(nInnerIndex > 1)
+ {
+ const awt::Point aPPrev2 = pInnerSequence[nInnerIndex - 2];
+ const drawing::PolygonFlags aFPrev2 = pInnerFlags[nInnerIndex - 2];
+ ::basegfx::B2DVector aVec1(aPPrev2.X - aPPrev1.X, aPPrev2.Y - aPPrev1.Y);
+ ::basegfx::B2DVector aVec2(nX1 - aPPrev1.X, nY1 - aPPrev1.Y);
+ bool bSameLength(false);
+ bool bSameDirection(false);
+
+ // get vector values
+ Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
+
+ if(drawing::PolygonFlags_CONTROL == aFPrev2)
+ {
+ // point before is a control point
+ if(bSameDirection)
+ {
+ if(bSameLength)
+ {
+ // set to PolygonFlags_SYMMETRIC
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
+ }
+ else
+ {
+ // set to PolygonFlags_SMOOTH
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
+ }
+ }
+ else
+ {
+ // set to PolygonFlags_NORMAL
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
+ }
+ }
+ else
+ {
+ // point before is a simple curve point
+ if(bSameDirection)
+ {
+ // set to PolygonFlags_SMOOTH
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
+ }
+ else
+ {
+ // set to PolygonFlags_NORMAL
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
+ }
+ }
+ }
+ else
+ {
+ // no point before starpoint, set type to PolygonFlags_NORMAL
+ pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
+ }
+ }
+}
+
+SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew,
+ const SdXMLImExViewBox& rViewBox,
+ const awt::Point& rObjectPos,
+ const awt::Size& rObjectSize,
+ const SvXMLUnitConverter& rConv)
+: msString( rNew ),
+ mrViewBox( rViewBox ),
+ mbIsClosed( false ),
+ mbIsCurve( false ),
+ mnLastX( 0L ),
+ mnLastY( 0L ),
+ maPoly( 0L ),
+ maFlag( 0L )
+{
+ // convert string to polygon
+ const OUString aStr(msString.getStr(), msString.getLength());
+ const sal_Int32 nLen(aStr.getLength());
+ sal_Int32 nPos(0);
+ sal_Int32 nNumPolys(0L);
+ bool bEllipticalArc(false);
+
+ // object size and ViewBox size different?
+ bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
+ || rObjectSize.Height != mrViewBox.GetHeight());
+ bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
+
+ // first loop: count polys and get flags
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen)
+ {
+ switch(aStr[nPos++])
+ {
+ case 'Z' :
+ case 'z' :
+ {
+ break;
+ }
+ case 'M' :
+ case 'm' :
+ {
+ nNumPolys++;
+ break;
+ }
+ case 'S' :
+ case 's' :
+ case 'C' :
+ case 'c' :
+ case 'Q' :
+ case 'q' :
+ case 'T' :
+ case 't' :
+ {
+ mbIsCurve = true;
+ break;
+ }
+ case 'L' :
+ case 'l' :
+ case 'H' :
+ case 'h' :
+ case 'V' :
+ case 'v' :
+ {
+ // normal, interpreted values. All okay.
+ break;
+ }
+ case 'A' :
+ case 'a' :
+ {
+ // Not yet interpreted value.
+ bEllipticalArc = true;
+ break;
+ }
+ }
+ }
+
+ DBG_ASSERT(!bEllipticalArc, "XMLIMP: non-interpreted tags in svg:d element!");
+
+ if(nNumPolys)
+ {
+ // alloc arrays
+ maPoly.realloc(nNumPolys);
+ if(IsCurve())
+ maFlag.realloc(nNumPolys);
+
+ // get outer sequences
+ drawing::PointSequence* pOuterSequence = maPoly.getArray();
+ drawing::FlagSequence* pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
+
+ // prepare new loop, count
+ sal_uInt32 nPointCount(0L);
+ nPos = 0;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // #104076# reset closed flag for next to be started polygon
+ mbIsClosed = false;
+
+ while(nPos < nLen)
+ {
+ switch(aStr[nPos])
+ {
+ case 'z' :
+ case 'Z' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // #104076# remember closed state of current polygon
+ mbIsClosed = true;
+
+ break;
+ }
+ case 'm' :
+ case 'M' :
+ {
+ // new poly starts, end-process current poly
+ if(nPointCount)
+ {
+ // #104076# If this partial polygon is closed, use one more point
+ // to represent that
+ if(mbIsClosed)
+ {
+ nPointCount++;
+ }
+
+ pOuterSequence->realloc(nPointCount);
+ pOuterSequence++;
+
+ if(pOuterFlags)
+ {
+ pOuterFlags->realloc(nPointCount);
+ pOuterFlags++;
+ }
+
+ // reset point count for next polygon
+ nPointCount = 0L;
+ }
+
+ // #104076# reset closed flag for next to be started polygon
+ mbIsClosed = false;
+
+ // NO break, continue in next case
+ }
+ case 'L' :
+ case 'l' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ nPointCount++;
+ }
+ break;
+ }
+ case 'H' :
+ case 'h' :
+ case 'V' :
+ case 'v' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ nPointCount++;
+ }
+ break;
+ }
+ case 'S' :
+ case 's' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ nPointCount += 3;
+ }
+ break;
+ }
+ case 'C' :
+ case 'c' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ nPointCount += 3;
+ }
+ break;
+ }
+
+ // #100617# quadratic beziers, supported as cubic ones
+ case 'Q' :
+ case 'q' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+
+ // use three points since quadratic is imported as cubic
+ nPointCount += 3;
+ }
+ break;
+ }
+
+ // #100617# relative quadratic beziers, supported as cubic ones
+ case 'T' :
+ case 't' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+
+ // use three points since quadratic is imported as cubic
+ nPointCount += 3;
+ }
+ break;
+ }
+
+ // #100617# not yet supported: elliptical arc
+ case 'A' :
+ case 'a' :
+ {
+ DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ }
+ break;
+ }
+
+ default:
+ {
+ nPos++;
+ DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
+ break;
+ }
+ }
+ }
+
+ // alloc last poly (when points used)
+ if(nPointCount)
+ {
+ // #104076# If this partial polygon is closed, use one more point
+ // to represent that
+ if(mbIsClosed)
+ {
+ nPointCount++;
+ }
+
+ pOuterSequence->realloc(nPointCount);
+ pOuterSequence++;
+
+ if(pOuterFlags)
+ {
+ pOuterFlags->realloc(nPointCount);
+ pOuterFlags++;
+ }
+ }
+
+ // set pointers back
+ pOuterSequence = maPoly.getArray();
+ pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
+ awt::Point* pNotSoInnerSequence = 0L;
+ drawing::PolygonFlags* pNotSoInnerFlags = 0L;
+ sal_uInt32 nInnerIndex(0L);
+
+ // prepare new loop, read points
+ nPos = 0;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // #104076# reset closed flag for next to be started polygon
+ mbIsClosed = false;
+
+ while(nPos < nLen)
+ {
+ bool bRelative(false);
+
+ switch(aStr[nPos])
+ {
+ case 'z' :
+ case 'Z' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ // #104076# remember closed state of current polygon
+ mbIsClosed = true;
+
+ // closed: add first point again
+ // sal_Int32 nX(pInnerSequence[0].X);
+ // sal_Int32 nY(pInnerSequence[0].Y);
+ // Imp_AddExportPoints(nX, nY, pInnerSequence, pInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+
+ break;
+ }
+
+ case 'm' :
+ {
+ bRelative = true;
+ }
+ case 'M' :
+ {
+ // #104076# end-process current poly
+ if(mbIsClosed)
+ {
+ if(pNotSoInnerSequence)
+ {
+ // closed: add first point again
+ sal_Int32 nX(pNotSoInnerSequence[0].X);
+ sal_Int32 nY(pNotSoInnerSequence[0].Y);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+
+ // reset closed flag for next to be started polygon
+ mbIsClosed = false;
+ }
+
+ // next poly
+ pNotSoInnerSequence = pOuterSequence->getArray();
+ pOuterSequence++;
+
+ if(pOuterFlags)
+ {
+ pNotSoInnerFlags = pOuterFlags->getArray();
+ pOuterFlags++;
+ }
+
+ nInnerIndex = 0L;
+
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform and add point and flag
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+ break;
+ }
+
+ case 'l' :
+ {
+ bRelative = true;
+ }
+ case 'L' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform and add point and flag
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+ break;
+ }
+
+ case 'h' :
+ {
+ bRelative = true;
+ }
+ case 'H' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(mnLastY);
+
+ if(bRelative)
+ nX += mnLastX;
+
+ // set last position
+ mnLastX = nX;
+
+ // calc transform and add point and flag
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+ break;
+ }
+
+ case 'v' :
+ {
+ bRelative = true;
+ }
+ case 'V' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX(mnLastX);
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ nY += mnLastY;
+
+ // set last position
+ mnLastY = nY;
+
+ // calc transform and add point and flag
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+ break;
+ }
+
+ case 's' :
+ {
+ bRelative = true;
+ }
+ case 'S' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX1;
+ sal_Int32 nY1;
+ sal_Int32 nX2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nX2 += mnLastX;
+ nY2 += mnLastY;
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform for new points
+ Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+
+ // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
+ // and the Point X1,Y1 can be constructed by mirroring the point before it.
+ nX1 = nX2;
+ nY1 = nY2;
+ if(nInnerIndex)
+ {
+ awt::Point aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
+
+ if(nInnerIndex > 1)
+ {
+ awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
+ nX1 = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
+ nY1 = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
+ }
+
+ // set curve point to symmetric
+ pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
+ }
+
+ // add calculated control point
+ Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+
+ // add new points and set flags
+ Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
+ }
+ break;
+ }
+
+ case 'c' :
+ {
+ bRelative = true;
+ }
+ case 'C' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nX1(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY1(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nX2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nX1 += mnLastX;
+ nY1 += mnLastY;
+ nX2 += mnLastX;
+ nY2 += mnLastY;
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform for new points
+ Imp_PrepareCoorImport(nX1, nY1, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+
+ // correct polygon flag for previous point
+ Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
+
+ // add new points and set flags
+ Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
+ }
+ break;
+ }
+
+ // #100617# quadratic beziers are imported as cubic
+ case 'q' :
+ {
+ bRelative = true;
+ }
+ case 'Q' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nXX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nYY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nXX += mnLastX;
+ nYY += mnLastY;
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform for new points
+ Imp_PrepareCoorImport(nXX, nYY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+
+ // calculate X1,X2
+ awt::Point aPPrev1 = (nInnerIndex) ? pNotSoInnerSequence[nInnerIndex-1] : pNotSoInnerSequence[0];
+ sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
+ sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
+ sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
+ sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
+
+ // correct polygon flag for previous point
+ Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
+
+ // add new points and set flags
+ Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
+ }
+ break;
+ }
+
+ // #100617# relative quadratic beziers are imported as cubic
+ case 't' :
+ {
+ bRelative = true;
+ }
+ case 'T' :
+ {
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ sal_Int32 nXX;
+ sal_Int32 nYY;
+ sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+ sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
+
+ if(bRelative)
+ {
+ nX += mnLastX;
+ nY += mnLastY;
+ }
+
+ // set last position
+ mnLastX = nX;
+ mnLastY = nY;
+
+ // calc transform for new points
+ Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
+
+ // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
+ // and the Point X1,Y1 can be constructed by mirroring the point before it.
+ nXX = nX;
+ nYY = nY;
+ awt::Point aPPrev1 = pNotSoInnerSequence[0];
+
+ if(nInnerIndex)
+ {
+ aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
+
+ if(nInnerIndex > 1)
+ {
+ awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
+ nXX = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
+ nYY = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
+ }
+
+ // set curve point to smooth here, since length
+ // is changed and thus only c1 can be used.
+ pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
+ }
+
+ // calculate X1,X2
+ sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
+ sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
+ sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
+ sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
+
+ // correct polygon flag for previous point
+ Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
+
+ // add new points and set flags
+ Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
+ }
+ break;
+ }
+
+ // #100617# not yet supported: elliptical arc
+ case 'A' :
+ case 'a' :
+ {
+ DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
+ nPos++;
+ Imp_SkipSpaces(aStr, nPos, nLen);
+
+ while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
+ {
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
+ }
+ break;
+ }
+
+ default:
+ {
+ nPos++;
+ DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
+ break;
+ }
+ }
+ }
+
+ // #104076# end-process closed state of last poly
+ if(mbIsClosed)
+ {
+ if(pNotSoInnerSequence)
+ {
+ // closed: add first point again
+ sal_Int32 nX(pNotSoInnerSequence[0].X);
+ sal_Int32 nY(pNotSoInnerSequence[0].Y);
+ Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
+ }
+ }
+
+ // #87202# If it's a curve and it's closed the last point maybe too much
+ // and just exported since SVG does not allow special handling of same
+ // start and end point, remove this last point.
+ // Evtl. correct the last curve flags, too.
+ if(IsCurve() && IsClosed())
+ {
+ // make one more loop over the PolyPolygon
+ pOuterSequence = maPoly.getArray();
+ pOuterFlags = maFlag.getArray();
+ sal_Int32 nOuterCnt(maPoly.getLength());
+
+ for(sal_Int32 a(0); a < nOuterCnt; a++)
+ {
+ // get Polygon pointers
+ awt::Point* pInnerSequence = pOuterSequence->getArray();
+ drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
+ sal_Int32 nInnerCnt(pOuterSequence->getLength());
+
+ while( nInnerCnt >= 2
+ && ((pInnerSequence + (nInnerCnt - 2))->X == (pInnerSequence + (nInnerCnt - 1))->X)
+ && ((pInnerSequence + (nInnerCnt - 2))->Y == (pInnerSequence + (nInnerCnt - 1))->Y)
+ && drawing::PolygonFlags_CONTROL != *(pInnerFlags + (nInnerCnt - 2)))
+ {
+ // remove last point from array
+ pOuterSequence->realloc(nInnerCnt - 1);
+ pOuterFlags->realloc(nInnerCnt - 1);
+
+ // get new pointers
+ pInnerSequence = pOuterSequence->getArray();
+ pInnerFlags = pOuterFlags->getArray();
+ nInnerCnt = pOuterSequence->getLength();
+ }
+
+ // now evtl. correct the last curve flags
+ if(nInnerCnt >= 4)
+ {
+ if( pInnerSequence->X == (pInnerSequence + (nInnerCnt - 1))->X
+ && pInnerSequence->Y == (pInnerSequence + (nInnerCnt - 1))->Y
+ && drawing::PolygonFlags_CONTROL == *(pInnerFlags + 1)
+ && drawing::PolygonFlags_CONTROL == *(pInnerFlags + (nInnerCnt - 2)))
+ {
+ awt::Point aPrev = *(pInnerSequence + (nInnerCnt - 2));
+ awt::Point aCurr = *pInnerSequence;
+ awt::Point aNext = *(pInnerSequence + 1);
+ ::basegfx::B2DVector aVec1(aPrev.X - aCurr.X, aPrev.Y - aCurr.Y);
+ ::basegfx::B2DVector aVec2(aNext.X - aCurr.X, aNext.Y - aCurr.Y);
+ bool bSameLength(false);
+ bool bSameDirection(false);
+
+ // get vector values
+ Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
+
+ // set correct flag value
+ if(bSameDirection)
+ {
+ if(bSameLength)
+ {
+ // set to PolygonFlags_SYMMETRIC
+ *pInnerFlags = drawing::PolygonFlags_SYMMETRIC;
+ *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SYMMETRIC;
+ }
+ else
+ {
+ // set to PolygonFlags_SMOOTH
+ *pInnerFlags = drawing::PolygonFlags_SMOOTH;
+ *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SMOOTH;
+ }
+ }
+ else
+ {
+ // set to PolygonFlags_NORMAL
+ *pInnerFlags = drawing::PolygonFlags_NORMAL;
+ *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_NORMAL;
+ }
+ }
+ }
+
+ // switch to next Polygon
+ pOuterSequence++;
+ pOuterFlags++;
+ }
+ }
+ }
+}
+
+// eof
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */