xref: /trunk/main/xmloff/source/draw/xexptran.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include "xexptran.hxx"
31 #include <tools/debug.hxx>
32 #include <rtl/ustrbuf.hxx>
33 #include <xmloff/xmluconv.hxx>
34 #include <tools/gen.hxx>
35 #include <basegfx/vector/b2dvector.hxx>
36 #include <basegfx/matrix/b2dhommatrix.hxx>
37 #include <basegfx/tuple/b3dtuple.hxx>
38 #include <basegfx/matrix/b3dhommatrix.hxx>
39 #include <tools/string.hxx>
40 
41 using ::rtl::OUString;
42 using ::rtl::OUStringBuffer;
43 
44 using namespace ::com::sun::star;
45 
46 //////////////////////////////////////////////////////////////////////////////
47 // Defines
48 
49 #define BORDER_INTEGERS_ARE_EQUAL       (4)
50 
51 //////////////////////////////////////////////////////////////////////////////
52 // Predeclarations
53 
54 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen);
55 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection);
56 
57 //////////////////////////////////////////////////////////////////////////////
58 //////////////////////////////////////////////////////////////////////////////
59 // parsing help functions for simple chars
60 void Imp_SkipSpaces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
61 {
62     while(rPos < nLen
63         && sal_Unicode(' ') == rStr[rPos])
64         rPos++;
65 }
66 
67 void Imp_SkipSpacesAndOpeningBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
68 {
69     while(rPos < nLen
70         && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode('(') == rStr[rPos]))
71         rPos++;
72 }
73 
74 void Imp_SkipSpacesAndCommas(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
75 {
76     while(rPos < nLen
77         && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(',') == rStr[rPos]))
78         rPos++;
79 }
80 
81 void Imp_SkipSpacesAndClosingBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
82 {
83     while(rPos < nLen
84         && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(')') == rStr[rPos]))
85         rPos++;
86 }
87 
88 //////////////////////////////////////////////////////////////////////////////
89 //////////////////////////////////////////////////////////////////////////////
90 // parsing help functions for integer numbers
91 
92 bool Imp_IsOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
93 {
94     sal_Unicode aChar(rStr[nPos]);
95 
96     if((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
97         || (bSignAllowed && sal_Unicode('+') == aChar)
98         || (bSignAllowed && sal_Unicode('-') == aChar)
99     )
100         return true;
101     return false;
102 }
103 
104 bool Imp_IsOnUnitChar(const OUString& rStr, const sal_Int32 nPos)
105 {
106     sal_Unicode aChar(rStr[nPos]);
107 
108     if((sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
109         || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
110         || sal_Unicode('%') == aChar
111     )
112         return true;
113     return false;
114 }
115 
116 void Imp_SkipNumber(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
117 {
118     bool bSignAllowed(true);
119 
120     while(rPos < nLen && Imp_IsOnNumberChar(rStr, rPos, bSignAllowed))
121     {
122         bSignAllowed = false;
123         rPos++;
124     }
125 }
126 
127 void Imp_SkipNumberAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
128     const sal_Int32 nLen)
129 {
130     Imp_SkipNumber(rStr, rPos, nLen);
131     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
132 }
133 
134 // #100617# Allow to skip doubles, too.
135 void Imp_SkipDoubleAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
136     const sal_Int32 nLen)
137 {
138     Imp_SkipDouble(rStr, rPos, nLen);
139     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
140 }
141 
142 void Imp_PutNumberChar(OUString& rStr, sal_Int32 nValue)
143 {
144     OUStringBuffer sStringBuffer;
145     SvXMLUnitConverter::convertNumber(sStringBuffer, nValue);
146     rStr += OUString(sStringBuffer.makeStringAndClear());
147 }
148 
149 void Imp_PutNumberCharWithSpace(OUString& rStr, sal_Int32 nValue)
150 {
151     const sal_Int32 aLen(rStr.getLength());
152     if(aLen)
153         if(Imp_IsOnNumberChar(rStr, aLen - 1, false) && nValue >= 0)
154             rStr += String(sal_Unicode(' '));
155     Imp_PutNumberChar(rStr, nValue);
156 }
157 
158 //////////////////////////////////////////////////////////////////////////////
159 //////////////////////////////////////////////////////////////////////////////
160 // parsing help functions for double numbers
161 
162 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32)
163 {
164     sal_Unicode aChar(rStr[rPos]);
165 
166     if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
167         aChar = rStr[++rPos];
168 
169     while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
170         || sal_Unicode('.') == aChar)
171     {
172         aChar = rStr[++rPos];
173     }
174 
175     if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
176     {
177         aChar = rStr[++rPos];
178 
179         if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
180             aChar = rStr[++rPos];
181 
182         while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
183         {
184             aChar = rStr[++rPos];
185         }
186     }
187 }
188 
189 double Imp_GetDoubleChar(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen,
190     const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false)
191 {
192     sal_Unicode aChar(rStr[rPos]);
193     OUStringBuffer sNumberString;
194 
195     if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
196     {
197         sNumberString.append(rStr[rPos]);
198         aChar = rStr[++rPos];
199     }
200 
201     while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
202         || sal_Unicode('.') == aChar)
203     {
204         sNumberString.append(rStr[rPos]);
205         aChar = rStr[++rPos];
206     }
207 
208     if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
209     {
210         sNumberString.append(rStr[rPos]);
211         aChar = rStr[++rPos];
212 
213         if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
214         {
215             sNumberString.append(rStr[rPos]);
216             aChar = rStr[++rPos];
217         }
218 
219         while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
220         {
221             sNumberString.append(rStr[rPos]);
222             aChar = rStr[++rPos];
223         }
224     }
225 
226     if(bLookForUnits)
227     {
228         Imp_SkipSpaces(rStr, rPos, nLen);
229         while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos))
230             sNumberString.append(rStr[rPos++]);
231     }
232 
233     if(sNumberString.getLength())
234     {
235         if(bLookForUnits)
236             rConv.convertDouble(fRetval, sNumberString.makeStringAndClear(), true);
237         else
238             rConv.convertDouble(fRetval, sNumberString.makeStringAndClear());
239     }
240 
241     return fRetval;
242 }
243 
244 void Imp_PutDoubleChar(OUString& rStr, const SvXMLUnitConverter& rConv, double fValue,
245     bool bConvertUnits = false)
246 {
247     OUStringBuffer sStringBuffer;
248 
249     if(bConvertUnits)
250         rConv.convertDouble(sStringBuffer, fValue, true);
251     else
252         rConv.convertDouble(sStringBuffer, fValue);
253 
254     rStr += OUString(sStringBuffer.makeStringAndClear());
255 }
256 
257 //////////////////////////////////////////////////////////////////////////////
258 //////////////////////////////////////////////////////////////////////////////
259 // base class of all 2D transform objects
260 
261 struct ImpSdXMLExpTransObj2DBase
262 {
263     sal_uInt16                  mnType;
264     ImpSdXMLExpTransObj2DBase(sal_uInt16 nType)
265     :   mnType(nType) {}
266 };
267 
268 //////////////////////////////////////////////////////////////////////////////
269 // possible object types for 2D
270 
271 #define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE          0x0000
272 #define IMP_SDXMLEXP_TRANSOBJ2D_SCALE           0x0001
273 #define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE       0x0002
274 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX           0x0003
275 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY           0x0004
276 #define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX          0x0005
277 
278 //////////////////////////////////////////////////////////////////////////////
279 // classes of objects, different sizes
280 
281 struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase
282 {
283     double                      mfRotate;
284     ImpSdXMLExpTransObj2DRotate(double fVal)
285     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {}
286 };
287 struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase
288 {
289     ::basegfx::B2DTuple         maScale;
290     ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew)
291     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {}
292 };
293 struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase
294 {
295     ::basegfx::B2DTuple         maTranslate;
296     ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew)
297     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {}
298 };
299 struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase
300 {
301     double                      mfSkewX;
302     ImpSdXMLExpTransObj2DSkewX(double fVal)
303     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {}
304 };
305 struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase
306 {
307     double                      mfSkewY;
308     ImpSdXMLExpTransObj2DSkewY(double fVal)
309     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {}
310 };
311 struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase
312 {
313     ::basegfx::B2DHomMatrix     maMatrix;
314     ImpSdXMLExpTransObj2DMatrix(const ::basegfx::B2DHomMatrix& rNew)
315     :   ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(rNew) {}
316 };
317 
318 //////////////////////////////////////////////////////////////////////////////
319 //////////////////////////////////////////////////////////////////////////////
320 // delete all entries in list
321 
322 void SdXMLImExTransform2D::EmptyList()
323 {
324     const sal_uInt32 nCount = maList.size();
325     for(sal_uInt32 a(0L); a < nCount; a++)
326     {
327         ImpSdXMLExpTransObj2DBase* pObj = maList[a];
328 
329         switch(pObj->mnType)
330         {
331             case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE     :
332             {
333                 delete (ImpSdXMLExpTransObj2DRotate*)pObj;
334                 break;
335             }
336             case IMP_SDXMLEXP_TRANSOBJ2D_SCALE      :
337             {
338                 delete (ImpSdXMLExpTransObj2DScale*)pObj;
339                 break;
340             }
341             case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE  :
342             {
343                 delete (ImpSdXMLExpTransObj2DTranslate*)pObj;
344                 break;
345             }
346             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX      :
347             {
348                 delete (ImpSdXMLExpTransObj2DSkewX*)pObj;
349                 break;
350             }
351             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY      :
352             {
353                 delete (ImpSdXMLExpTransObj2DSkewY*)pObj;
354                 break;
355             }
356             case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX     :
357             {
358                 delete (ImpSdXMLExpTransObj2DMatrix*)pObj;
359                 break;
360             }
361             default :
362             {
363                 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
364                 break;
365             }
366         }
367     }
368 
369     maList.clear();
370 }
371 
372 //////////////////////////////////////////////////////////////////////////////
373 // add members
374 
375 void SdXMLImExTransform2D::AddRotate(double fNew)
376 {
377     if(fNew != 0.0)
378         maList.push_back(new ImpSdXMLExpTransObj2DRotate(fNew));
379 }
380 
381 void SdXMLImExTransform2D::AddScale(const ::basegfx::B2DTuple& rNew)
382 {
383     if(1.0 != rNew.getX() || 1.0 != rNew.getY())
384         maList.push_back(new ImpSdXMLExpTransObj2DScale(rNew));
385 }
386 
387 void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew)
388 {
389     if(!rNew.equalZero())
390         maList.push_back(new ImpSdXMLExpTransObj2DTranslate(rNew));
391 }
392 
393 void SdXMLImExTransform2D::AddSkewX(double fNew)
394 {
395     if(fNew != 0.0)
396         maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fNew));
397 }
398 
399 void SdXMLImExTransform2D::AddSkewY(double fNew)
400 {
401     if(fNew != 0.0)
402         maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fNew));
403 }
404 
405 void SdXMLImExTransform2D::AddMatrix(const ::basegfx::B2DHomMatrix& rNew)
406 {
407     if(!rNew.isIdentity())
408         maList.push_back(new ImpSdXMLExpTransObj2DMatrix(rNew));
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////
412 // gen string for export
413 const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv)
414 {
415     OUString aNewString;
416     OUString aClosingBrace(sal_Unicode(')'));
417     OUString aEmptySpace(sal_Unicode(' '));
418 
419     const sal_uInt32 nCount = maList.size();
420     for(sal_uInt32 a(0L); a < nCount; a++)
421     {
422         ImpSdXMLExpTransObj2DBase* pObj = maList[a];
423         switch(pObj->mnType)
424         {
425             case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
426             {
427                 aNewString += OUString::createFromAscii("rotate (");
428                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate);
429                 aNewString += aClosingBrace;
430                 break;
431             }
432             case IMP_SDXMLEXP_TRANSOBJ2D_SCALE      :
433             {
434                 aNewString += OUString::createFromAscii("scale (");
435                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getX());
436                 aNewString += aEmptySpace;
437                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getY());
438                 aNewString += aClosingBrace;
439                 break;
440             }
441             case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE  :
442             {
443                 aNewString += OUString::createFromAscii("translate (");
444                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getX(), true);
445                 aNewString += aEmptySpace;
446                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getY(), true);
447                 aNewString += aClosingBrace;
448                 break;
449             }
450             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX      :
451             {
452                 aNewString += OUString::createFromAscii("skewX (");
453                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX);
454                 aNewString += aClosingBrace;
455                 break;
456             }
457             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY      :
458             {
459                 aNewString += OUString::createFromAscii("skewY (");
460                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY);
461                 aNewString += aClosingBrace;
462                 break;
463             }
464             case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
465             {
466                 aNewString += OUString::createFromAscii("matrix (");
467 
468                 // a
469                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 0));
470                 aNewString += aEmptySpace;
471 
472                 // b
473                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 0));
474                 aNewString += aEmptySpace;
475 
476                 // c
477                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 1));
478                 aNewString += aEmptySpace;
479 
480                 // d
481                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 1));
482                 aNewString += aEmptySpace;
483 
484                 // e
485                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 2), true);
486                 aNewString += aEmptySpace;
487 
488                 // f
489                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 2), true);
490 
491                 aNewString += aClosingBrace;
492                 break;
493             }
494             default :
495             {
496                 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
497                 break;
498             }
499         }
500 
501         // if not the last entry, add one space to next tag
502         if(a + 1UL != maList.size())
503         {
504             aNewString += aEmptySpace;
505         }
506     }
507 
508     // fill string form OUString
509     msString = aNewString;
510 
511     return msString;
512 }
513 
514 //////////////////////////////////////////////////////////////////////////////
515 // for Import: constructor with string, parses it and generates entries
516 SdXMLImExTransform2D::SdXMLImExTransform2D(const OUString& rNew, const SvXMLUnitConverter& rConv)
517 {
518     SetString(rNew, rConv);
519 }
520 
521 //////////////////////////////////////////////////////////////////////////////
522 // sets new string, parses it and generates entries
523 void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
524 {
525     msString = rNew;
526     EmptyList();
527 
528     if(msString.getLength())
529     {
530         const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
531         const sal_Int32 nLen(aStr.getLength());
532 
533         const OUString aString_rotate(OUString::createFromAscii("rotate"));
534         const OUString aString_scale(OUString::createFromAscii("scale"));
535         const OUString aString_translate(OUString::createFromAscii("translate"));
536         const OUString aString_skewX(OUString::createFromAscii("skewX"));
537         const OUString aString_skewY(OUString::createFromAscii("skewY"));
538         const OUString aString_matrix(OUString::createFromAscii("matrix"));
539 
540         sal_Int32 nPos(0);
541 
542         while(nPos < nLen)
543         {
544             // skip spaces
545             Imp_SkipSpaces(aStr, nPos, nLen);
546 
547             // look for tag
548             if(nPos < nLen)
549             {
550                 if(nPos == aStr.indexOf(aString_rotate, nPos))
551                 {
552                     double fValue(0.0);
553                     nPos += 6;
554                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
555                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
556                     if(fValue != 0.0)
557                         maList.push_back(new ImpSdXMLExpTransObj2DRotate(fValue));
558 
559                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
560                 }
561                 else if(nPos == aStr.indexOf(aString_scale, nPos))
562                 {
563                     ::basegfx::B2DTuple aValue(1.0, 1.0);
564                     nPos += 5;
565                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
566                     aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
567                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
568                     aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
569 
570                     if(aValue.getX() != 1.0 || aValue.getY() != 1.0)
571                         maList.push_back(new ImpSdXMLExpTransObj2DScale(aValue));
572 
573                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
574                 }
575                 else if(nPos == aStr.indexOf(aString_translate, nPos))
576                 {
577                     ::basegfx::B2DTuple aValue;
578                     nPos += 9;
579                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
580                     aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
581                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
582                     aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
583 
584                     if(!aValue.equalZero())
585                         maList.push_back(new ImpSdXMLExpTransObj2DTranslate(aValue));
586 
587                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
588                 }
589                 else if(nPos == aStr.indexOf(aString_skewX, nPos))
590                 {
591                     double fValue(0.0);
592                     nPos += 5;
593                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
594                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
595                     if(fValue != 0.0)
596                         maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fValue));
597 
598                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
599                 }
600                 else if(nPos == aStr.indexOf(aString_skewY, nPos))
601                 {
602                     double fValue(0.0);
603                     nPos += 5;
604                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
605                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
606                     if(fValue != 0.0)
607                         maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fValue));
608 
609                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
610                 }
611                 else if(nPos == aStr.indexOf(aString_matrix, nPos))
612                 {
613                     ::basegfx::B2DHomMatrix aValue;
614 
615                     nPos += 6;
616                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
617 
618                     // a
619                     aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
620                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
621 
622                     // b
623                     aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
624                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
625 
626                     // c
627                     aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
628                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
629 
630                     // d
631                     aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
632                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
633 
634                     // e
635                     aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true));
636                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
637 
638                     // f
639                     aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true));
640                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
641 
642                     if(!aValue.isIdentity())
643                         maList.push_back(new ImpSdXMLExpTransObj2DMatrix(aValue));
644 
645                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
646                 }
647                 else
648                 {
649                     nPos++;
650                 }
651             }
652         }
653     }
654 }
655 
656 void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans)
657 {
658     rFullTrans.identity();
659 
660     const sal_uInt32 nCount = maList.size();
661     for(sal_uInt32 a(0L); a < nCount; a++)
662     {
663         ImpSdXMLExpTransObj2DBase* pObj = maList[a];
664         switch(pObj->mnType)
665         {
666             case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE     :
667             {
668                 // #i78696#
669                 // mfRotate is mathematically wrong oriented since we export/import the angle
670                 // values mirrored. This error is fixed in the API, but not yet in the FileFormat.
671                 // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next
672                 // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary
673                 // to mirror the value here
674                 rFullTrans.rotate(((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate * -1.0);
675                 break;
676             }
677             case IMP_SDXMLEXP_TRANSOBJ2D_SCALE      :
678             {
679                 const ::basegfx::B2DTuple& rScale = ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale;
680                 rFullTrans.scale(rScale.getX(), rScale.getY());
681                 break;
682             }
683             case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE  :
684             {
685                 const ::basegfx::B2DTuple& rTranslate = ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate;
686                 rFullTrans.translate(rTranslate.getX(), rTranslate.getY());
687                 break;
688             }
689             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX      :
690             {
691                 rFullTrans.shearX(tan(((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX));
692                 break;
693             }
694             case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY      :
695             {
696                 rFullTrans.shearY(tan(((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY));
697                 break;
698             }
699             case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX     :
700             {
701                 rFullTrans *= ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix;
702                 break;
703             }
704             default :
705             {
706                 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
707                 break;
708             }
709         }
710     }
711 }
712 
713 //////////////////////////////////////////////////////////////////////////////
714 //////////////////////////////////////////////////////////////////////////////
715 // base class of all 3D transform objects
716 
717 struct ImpSdXMLExpTransObj3DBase
718 {
719     sal_uInt16                  mnType;
720     ImpSdXMLExpTransObj3DBase(sal_uInt16 nType)
721     :   mnType(nType) {}
722 };
723 
724 //////////////////////////////////////////////////////////////////////////////
725 // possible object types for 3D
726 
727 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X        0x0000
728 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y        0x0001
729 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z        0x0002
730 #define IMP_SDXMLEXP_TRANSOBJ3D_SCALE           0x0003
731 #define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE       0x0004
732 #define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX          0x0005
733 
734 //////////////////////////////////////////////////////////////////////////////
735 // classes of objects, different sizes
736 
737 struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase
738 {
739     double                      mfRotateX;
740     ImpSdXMLExpTransObj3DRotateX(double fVal)
741     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {}
742 };
743 struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase
744 {
745     double                      mfRotateY;
746     ImpSdXMLExpTransObj3DRotateY(double fVal)
747     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {}
748 };
749 struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase
750 {
751     double                      mfRotateZ;
752     ImpSdXMLExpTransObj3DRotateZ(double fVal)
753     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {}
754 };
755 struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase
756 {
757     ::basegfx::B3DTuple         maScale;
758     ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew)
759     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {}
760 };
761 struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase
762 {
763     ::basegfx::B3DTuple         maTranslate;
764     ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew)
765     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {}
766 };
767 struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase
768 {
769     ::basegfx::B3DHomMatrix     maMatrix;
770     ImpSdXMLExpTransObj3DMatrix(const ::basegfx::B3DHomMatrix& rNew)
771     :   ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(rNew) {}
772 };
773 
774 //////////////////////////////////////////////////////////////////////////////
775 //////////////////////////////////////////////////////////////////////////////
776 // delete all entries in list
777 
778 void SdXMLImExTransform3D::EmptyList()
779 {
780     const sal_uInt32 nCount = maList.size();
781     for(sal_uInt32 a(0L); a < nCount; a++)
782     {
783         ImpSdXMLExpTransObj3DBase* pObj = maList[a];
784 
785         switch(pObj->mnType)
786         {
787             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X   :
788             {
789                 delete (ImpSdXMLExpTransObj3DRotateX*)pObj;
790                 break;
791             }
792             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y   :
793             {
794                 delete (ImpSdXMLExpTransObj3DRotateY*)pObj;
795                 break;
796             }
797             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z   :
798             {
799                 delete (ImpSdXMLExpTransObj3DRotateZ*)pObj;
800                 break;
801             }
802             case IMP_SDXMLEXP_TRANSOBJ3D_SCALE      :
803             {
804                 delete (ImpSdXMLExpTransObj3DScale*)pObj;
805                 break;
806             }
807             case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE  :
808             {
809                 delete (ImpSdXMLExpTransObj3DTranslate*)pObj;
810                 break;
811             }
812             case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX     :
813             {
814                 delete (ImpSdXMLExpTransObj3DMatrix*)pObj;
815                 break;
816             }
817             default :
818             {
819                 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
820                 break;
821             }
822         }
823     }
824 
825     maList.clear();
826 }
827 
828 //////////////////////////////////////////////////////////////////////////////
829 // add members
830 
831 void SdXMLImExTransform3D::AddRotateX(double fNew)
832 {
833     if(fNew != 0.0)
834         maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fNew));
835 }
836 
837 void SdXMLImExTransform3D::AddRotateY(double fNew)
838 {
839     if(fNew != 0.0)
840         maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fNew));
841 }
842 
843 void SdXMLImExTransform3D::AddRotateZ(double fNew)
844 {
845     if(fNew != 0.0)
846         maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fNew));
847 }
848 
849 void SdXMLImExTransform3D::AddScale(const ::basegfx::B3DTuple& rNew)
850 {
851     if(1.0 != rNew.getX() || 1.0 != rNew.getY() || 1.0 != rNew.getZ())
852         maList.push_back(new ImpSdXMLExpTransObj3DScale(rNew));
853 }
854 
855 void SdXMLImExTransform3D::AddTranslate(const ::basegfx::B3DTuple& rNew)
856 {
857     if(!rNew.equalZero())
858         maList.push_back(new ImpSdXMLExpTransObj3DTranslate(rNew));
859 }
860 
861 void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew)
862 {
863     if(!rNew.isIdentity())
864         maList.push_back(new ImpSdXMLExpTransObj3DMatrix(rNew));
865 }
866 
867 void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat)
868 {
869     ::basegfx::B3DHomMatrix aExportMatrix;
870 
871     aExportMatrix.set(0, 0, xHomMat.Line1.Column1);
872     aExportMatrix.set(0, 1, xHomMat.Line1.Column2);
873     aExportMatrix.set(0, 2, xHomMat.Line1.Column3);
874     aExportMatrix.set(0, 3, xHomMat.Line1.Column4);
875     aExportMatrix.set(1, 0, xHomMat.Line2.Column1);
876     aExportMatrix.set(1, 1, xHomMat.Line2.Column2);
877     aExportMatrix.set(1, 2, xHomMat.Line2.Column3);
878     aExportMatrix.set(1, 3, xHomMat.Line2.Column4);
879     aExportMatrix.set(2, 0, xHomMat.Line3.Column1);
880     aExportMatrix.set(2, 1, xHomMat.Line3.Column2);
881     aExportMatrix.set(2, 2, xHomMat.Line3.Column3);
882     aExportMatrix.set(2, 3, xHomMat.Line3.Column4);
883 
884     AddMatrix(aExportMatrix);
885 }
886 
887 //////////////////////////////////////////////////////////////////////////////
888 // gen string for export
889 const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv)
890 {
891     OUString aNewString;
892     OUString aClosingBrace(sal_Unicode(')'));
893     OUString aEmptySpace(sal_Unicode(' '));
894 
895     const sal_uInt32 nCount = maList.size();
896     for(sal_uInt32 a(0L); a < nCount; a++)
897     {
898         ImpSdXMLExpTransObj3DBase* pObj = maList[a];
899         switch(pObj->mnType)
900         {
901             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X   :
902             {
903                 aNewString += OUString::createFromAscii("rotatex (");
904                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX);
905                 aNewString += aClosingBrace;
906                 break;
907             }
908             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y   :
909             {
910                 aNewString += OUString::createFromAscii("rotatey (");
911                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY);
912                 aNewString += aClosingBrace;
913                 break;
914             }
915             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z   :
916             {
917                 aNewString += OUString::createFromAscii("rotatez (");
918                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
919                 aNewString += aClosingBrace;
920                 break;
921             }
922             case IMP_SDXMLEXP_TRANSOBJ3D_SCALE      :
923             {
924                 aNewString += OUString::createFromAscii("scale (");
925                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getX());
926                 aNewString += aEmptySpace;
927                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getY());
928                 aNewString += aEmptySpace;
929                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getZ());
930                 aNewString += aClosingBrace;
931                 break;
932             }
933             case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE  :
934             {
935                 aNewString += OUString::createFromAscii("translate (");
936                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getX(), true);
937                 aNewString += aEmptySpace;
938                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getY(), true);
939                 aNewString += aEmptySpace;
940                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getZ(), true);
941                 aNewString += aClosingBrace;
942                 break;
943             }
944             case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
945             {
946                 aNewString += OUString::createFromAscii("matrix (");
947 
948                 // a
949                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 0));
950                 aNewString += aEmptySpace;
951 
952                 // b
953                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 0));
954                 aNewString += aEmptySpace;
955 
956                 // c
957                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 0));
958                 aNewString += aEmptySpace;
959 
960                 // d
961                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 1));
962                 aNewString += aEmptySpace;
963 
964                 // e
965                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 1));
966                 aNewString += aEmptySpace;
967 
968                 // f
969                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 1));
970                 aNewString += aEmptySpace;
971 
972                 // g
973                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 2));
974                 aNewString += aEmptySpace;
975 
976                 // h
977                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 2));
978                 aNewString += aEmptySpace;
979 
980                 // i
981                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 2));
982                 aNewString += aEmptySpace;
983 
984                 // j
985                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 3), true);
986                 aNewString += aEmptySpace;
987 
988                 // k
989                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 3), true);
990                 aNewString += aEmptySpace;
991 
992                 // l
993                 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 3), true);
994 
995                 aNewString += aClosingBrace;
996                 break;
997             }
998             default :
999             {
1000                 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
1001                 break;
1002             }
1003         }
1004 
1005         // if not the last entry, add one space to next tag
1006         if(a + 1UL != maList.size())
1007         {
1008             aNewString += aEmptySpace;
1009         }
1010     }
1011 
1012     // fill string form OUString
1013     msString = aNewString;
1014 
1015     return msString;
1016 }
1017 
1018 //////////////////////////////////////////////////////////////////////////////
1019 // for Import: constructor with string, parses it and generates entries
1020 SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv)
1021 {
1022     SetString(rNew, rConv);
1023 }
1024 
1025 //////////////////////////////////////////////////////////////////////////////
1026 // sets new string, parses it and generates entries
1027 void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
1028 {
1029     msString = rNew;
1030     EmptyList();
1031 
1032     if(msString.getLength())
1033     {
1034         const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1035         const sal_Int32 nLen(aStr.getLength());
1036 
1037         const OUString aString_rotatex(OUString::createFromAscii("rotatex"));
1038         const OUString aString_rotatey(OUString::createFromAscii("rotatey"));
1039         const OUString aString_rotatez(OUString::createFromAscii("rotatez"));
1040         const OUString aString_scale(OUString::createFromAscii("scale"));
1041         const OUString aString_translate(OUString::createFromAscii("translate"));
1042         const OUString aString_matrix(OUString::createFromAscii("matrix"));
1043 
1044         sal_Int32 nPos(0);
1045 
1046         while(nPos < nLen)
1047         {
1048             // skip spaces
1049             Imp_SkipSpaces(aStr, nPos, nLen);
1050 
1051             // look for tag
1052             if(nPos < nLen)
1053             {
1054                 if(nPos == aStr.indexOf(aString_rotatex, nPos))
1055                 {
1056                     double fValue(0.0);
1057 
1058                     nPos += 7;
1059                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1060                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1061                     if(fValue != 0.0)
1062                         maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fValue));
1063 
1064                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1065                 }
1066                 else if(nPos == aStr.indexOf(aString_rotatey, nPos))
1067                 {
1068                     double fValue(0.0);
1069 
1070                     nPos += 7;
1071                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1072                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1073                     if(fValue != 0.0)
1074                         maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fValue));
1075 
1076                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1077                 }
1078                 else if(nPos == aStr.indexOf(aString_rotatez, nPos))
1079                 {
1080                     double fValue(0.0);
1081 
1082                     nPos += 7;
1083                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1084                     fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1085                     if(fValue != 0.0)
1086                         maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fValue));
1087 
1088                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1089                 }
1090                 else if(nPos == aStr.indexOf(aString_scale, nPos))
1091                 {
1092                     ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0);
1093 
1094                     nPos += 5;
1095                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1096                     aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
1097                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1098                     aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
1099                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1100                     aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ()));
1101 
1102                     if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ())
1103                         maList.push_back(new ImpSdXMLExpTransObj3DScale(aValue));
1104 
1105                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1106                 }
1107                 else if(nPos == aStr.indexOf(aString_translate, nPos))
1108                 {
1109                     ::basegfx::B3DTuple aValue;
1110 
1111                     nPos += 9;
1112                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1113                     aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
1114                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1115                     aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
1116                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1117                     aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true));
1118 
1119                     if(!aValue.equalZero())
1120                         maList.push_back(new ImpSdXMLExpTransObj3DTranslate(aValue));
1121 
1122                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1123                 }
1124                 else if(nPos == aStr.indexOf(aString_matrix, nPos))
1125                 {
1126                     ::basegfx::B3DHomMatrix aValue;
1127 
1128                     nPos += 6;
1129                     Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1130 
1131                     // a
1132                     aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
1133                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1134 
1135                     // b
1136                     aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
1137                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1138 
1139                     // c
1140                     aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0)));
1141                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1142 
1143                     // d
1144                     aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
1145                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1146 
1147                     // e
1148                     aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
1149                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1150 
1151                     // f
1152                     aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1)));
1153                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1154 
1155                     // g
1156                     aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2)));
1157                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1158 
1159                     // h
1160                     aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2)));
1161                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1162 
1163                     // i
1164                     aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2)));
1165                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1166 
1167                     // j
1168                     aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true));
1169                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1170 
1171                     // k
1172                     aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true));
1173                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1174 
1175                     // l
1176                     aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true));
1177                     Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1178 
1179                     if(!aValue.isIdentity())
1180                         maList.push_back(new ImpSdXMLExpTransObj3DMatrix(aValue));
1181 
1182                     Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1183                 }
1184                 else
1185                 {
1186                     nPos++;
1187                 }
1188             }
1189         }
1190     }
1191 }
1192 
1193 bool SdXMLImExTransform3D::GetFullHomogenTransform(com::sun::star::drawing::HomogenMatrix& xHomMat)
1194 {
1195     ::basegfx::B3DHomMatrix aFullTransform;
1196     GetFullTransform(aFullTransform);
1197 
1198     if(!aFullTransform.isIdentity())
1199     {
1200         xHomMat.Line1.Column1 = aFullTransform.get(0, 0);
1201         xHomMat.Line1.Column2 = aFullTransform.get(0, 1);
1202         xHomMat.Line1.Column3 = aFullTransform.get(0, 2);
1203         xHomMat.Line1.Column4 = aFullTransform.get(0, 3);
1204 
1205         xHomMat.Line2.Column1 = aFullTransform.get(1, 0);
1206         xHomMat.Line2.Column2 = aFullTransform.get(1, 1);
1207         xHomMat.Line2.Column3 = aFullTransform.get(1, 2);
1208         xHomMat.Line2.Column4 = aFullTransform.get(1, 3);
1209 
1210         xHomMat.Line3.Column1 = aFullTransform.get(2, 0);
1211         xHomMat.Line3.Column2 = aFullTransform.get(2, 1);
1212         xHomMat.Line3.Column3 = aFullTransform.get(2, 2);
1213         xHomMat.Line3.Column4 = aFullTransform.get(2, 3);
1214 
1215         xHomMat.Line4.Column1 = aFullTransform.get(3, 0);
1216         xHomMat.Line4.Column2 = aFullTransform.get(3, 1);
1217         xHomMat.Line4.Column3 = aFullTransform.get(3, 2);
1218         xHomMat.Line4.Column4 = aFullTransform.get(3, 3);
1219 
1220         return true;
1221     }
1222 
1223     return false;
1224 }
1225 
1226 void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans)
1227 {
1228     rFullTrans.identity();
1229 
1230     const sal_uInt32 nCount = maList.size();
1231     for(sal_uInt32 a(0L); a < nCount; a++)
1232     {
1233         ImpSdXMLExpTransObj3DBase* pObj = maList[a];
1234         switch(pObj->mnType)
1235         {
1236             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X   :
1237             {
1238                 rFullTrans.rotate(((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX, 0.0, 0.0);
1239                 break;
1240             }
1241             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y   :
1242             {
1243                 rFullTrans.rotate(0.0, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY, 0.0);
1244                 break;
1245             }
1246             case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z   :
1247             {
1248                 rFullTrans.rotate(0.0, 0.0, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
1249                 break;
1250             }
1251             case IMP_SDXMLEXP_TRANSOBJ3D_SCALE      :
1252             {
1253                 const ::basegfx::B3DTuple& rScale = ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale;
1254                 rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ());
1255                 break;
1256             }
1257             case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE  :
1258             {
1259                 const ::basegfx::B3DTuple& rTranslate = ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate;
1260                 rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
1261                 break;
1262             }
1263             case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX     :
1264             {
1265                 rFullTrans *= ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix;
1266                 break;
1267             }
1268             default :
1269             {
1270                 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
1271                 break;
1272             }
1273         }
1274     }
1275 }
1276 
1277 //////////////////////////////////////////////////////////////////////////////
1278 //////////////////////////////////////////////////////////////////////////////
1279 
1280 SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX, sal_Int32 nY, sal_Int32 nW, sal_Int32 nH)
1281 :   mnX( nX ),
1282     mnY( nY ),
1283     mnW( nW ),
1284     mnH( nH )
1285 {
1286 }
1287 
1288 // #100617# Asked vincent hardy: svg:viewBox values may be double precision.
1289 SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv)
1290 :   msString(rNew),
1291     mnX( 0L ),
1292     mnY( 0L ),
1293     mnW( 1000L ),
1294     mnH( 1000L )
1295 {
1296     if(msString.getLength())
1297     {
1298         const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1299         const sal_Int32 nLen(aStr.getLength());
1300         sal_Int32 nPos(0);
1301 
1302         // skip starting spaces
1303         Imp_SkipSpaces(aStr, nPos, nLen);
1304 
1305         // get mX, #100617# be prepared for doubles
1306         mnX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnX));
1307 
1308         // skip spaces and commas
1309         Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1310 
1311         // get mY, #100617# be prepared for doubles
1312         mnY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnY));
1313 
1314         // skip spaces and commas
1315         Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1316 
1317         // get mW, #100617# be prepared for doubles
1318         mnW = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnW));
1319 
1320         // skip spaces and commas
1321         Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1322 
1323         // get mH, #100617# be prepared for doubles
1324         mnH = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnH));
1325     }
1326 }
1327 
1328 const OUString& SdXMLImExViewBox::GetExportString()
1329 {
1330     OUString aNewString;
1331     OUString aEmptySpace(sal_Unicode(' '));
1332 
1333     Imp_PutNumberChar(aNewString, mnX);
1334     aNewString += aEmptySpace;
1335 
1336     Imp_PutNumberChar(aNewString, mnY);
1337     aNewString += aEmptySpace;
1338 
1339     Imp_PutNumberChar(aNewString, mnW);
1340     aNewString += aEmptySpace;
1341 
1342     Imp_PutNumberChar(aNewString, mnH);
1343 
1344     // set new string
1345     msString = aNewString;
1346 
1347     return msString;
1348 }
1349 
1350 //////////////////////////////////////////////////////////////////////////////
1351 //////////////////////////////////////////////////////////////////////////////
1352 
1353 SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence* pPoints,
1354     const SdXMLImExViewBox& rViewBox,
1355     const awt::Point& rObjectPos,
1356     const awt::Size& rObjectSize,
1357     // #96328#
1358     const bool bClosed)
1359 :   maPoly( 0L )
1360 {
1361     DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExPointsElement(!)");
1362 
1363     // add polygon to string
1364     sal_Int32 nCnt(pPoints->getLength());
1365 
1366     // #104076# Convert to string only when at last one point included
1367     if(nCnt > 0)
1368     {
1369         OUString aNewString;
1370         awt::Point* pArray = pPoints->getArray();
1371 
1372         // last point same? Ignore it.
1373         // #96328# ...but only when polygon is CLOSED
1374         if(bClosed && (pArray->X == (pArray + (nCnt - 1))->X) && (pArray->Y == (pArray + (nCnt - 1))->Y))
1375             nCnt--;
1376 
1377         // object size and ViewBox size different?
1378         bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1379             || rObjectSize.Height != rViewBox.GetHeight());
1380         bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1381 
1382         for(sal_Int32 a(0L); a < nCnt; a++)
1383         {
1384             // prepare coordinates
1385             sal_Int32 nX( pArray->X - rObjectPos.X );
1386             sal_Int32 nY( pArray->Y - rObjectPos.Y );
1387 
1388             if(bScale && rObjectSize.Width && rObjectSize.Height)
1389             {
1390                 nX = (nX * rViewBox.GetWidth()) / rObjectSize.Width;
1391                 nY = (nY * rViewBox.GetHeight()) / rObjectSize.Height;
1392             }
1393 
1394             if(bTranslate)
1395             {
1396                 nX += rViewBox.GetX();
1397                 nY += rViewBox.GetY();
1398             }
1399 
1400             // X and comma
1401             Imp_PutNumberChar(aNewString, nX);
1402             aNewString += String(sal_Unicode(','));
1403 
1404             // Y and space (not for last)
1405             Imp_PutNumberChar(aNewString, nY);
1406             if(a + 1 != nCnt)
1407                 aNewString += String(sal_Unicode(' '));
1408 
1409             // next point
1410             pArray++;
1411         }
1412 
1413         // set new string
1414         msString = aNewString;
1415     }
1416 }
1417 
1418 // #100617# svg:polyline or svg:polygon values may be double precision.
1419 SdXMLImExPointsElement::SdXMLImExPointsElement(const OUString& rNew,
1420     const SdXMLImExViewBox& rViewBox,
1421     const awt::Point& rObjectPos,
1422     const awt::Size& rObjectSize,
1423     const SvXMLUnitConverter& rConv)
1424 :   msString( rNew ),
1425     maPoly( 0L )
1426 {
1427     // convert string to polygon
1428     const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1429     const sal_Int32 nLen(aStr.getLength());
1430     sal_Int32 nPos(0);
1431     sal_Int32 nNumPoints(0L);
1432 
1433     // skip starting spaces
1434     Imp_SkipSpaces(aStr, nPos, nLen);
1435 
1436     // count points in first loop
1437     while(nPos < nLen)
1438     {
1439         // skip number, #100617# be prepared for doubles
1440         Imp_SkipDouble(aStr, nPos, nLen);
1441 
1442         // skip spaces and commas
1443         Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1444 
1445         // skip number, #100617# be prepared for doubles
1446         Imp_SkipDouble(aStr, nPos, nLen);
1447 
1448         // skip spaces and commas
1449         Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1450 
1451         // one more point
1452         nNumPoints++;
1453     }
1454 
1455     // second loop
1456     if(nNumPoints)
1457     {
1458         nPos = 0;
1459         maPoly.realloc(1);
1460         drawing::PointSequence* pOuterSequence = maPoly.getArray();
1461         pOuterSequence->realloc(nNumPoints);
1462         awt::Point* pInnerSequence = pOuterSequence->getArray();
1463 
1464         // object size and ViewBox size different?
1465         bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1466             || rObjectSize.Height != rViewBox.GetHeight());
1467         bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1468 
1469         // skip starting spaces
1470         Imp_SkipSpaces(aStr, nPos, nLen);
1471 
1472         while(nPos < nLen)
1473         {
1474             // prepare new parameter pair
1475             sal_Int32 nX(0L);
1476             sal_Int32 nY(0L);
1477 
1478             // get mX, #100617# be prepared for doubles
1479             nX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nX));
1480 
1481             // skip spaces and commas
1482             Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1483 
1484             // get mY, #100617# be prepared for doubles
1485             nY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nY));
1486 
1487             // skip spaces and commas
1488             Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1489 
1490             // prepare parameters
1491             if(bTranslate)
1492             {
1493                 nX -= rViewBox.GetX();
1494                 nY -= rViewBox.GetY();
1495             }
1496 
1497             if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight() )
1498             {
1499                 nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
1500                 nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
1501             }
1502 
1503             nX += rObjectPos.X;
1504             nY += rObjectPos.Y;
1505 
1506             // add new point
1507             *pInnerSequence = awt::Point( nX, nY );
1508             pInnerSequence++;
1509         }
1510     }
1511 }
1512 
1513 //////////////////////////////////////////////////////////////////////////////
1514 //////////////////////////////////////////////////////////////////////////////
1515 
1516 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox)
1517 :   mrViewBox( rViewBox ),
1518     mbIsClosed( false ),
1519     mbIsCurve( false ),
1520     mnLastX( 0L ),
1521     mnLastY( 0L ),
1522     maPoly( 0L ),
1523     maFlag( 0L )
1524 {
1525 }
1526 
1527 void Imp_GetPrevPos(awt::Point*& pPrevPos1,
1528     drawing::PolygonFlags& aPrevFlag1,
1529     const bool bClosed, awt::Point* pPoints,
1530     drawing::PolygonFlags* pFlags, const sal_Int32 nPos,
1531     const sal_Int32 nCnt, const sal_Int32 nAdd)
1532 {
1533     if(bClosed)
1534     {
1535         pPrevPos1 = pPoints + ((nPos + nCnt - nAdd) % nCnt);
1536         aPrevFlag1 = *(pFlags + ((nPos + nCnt - nAdd) % nCnt));
1537     }
1538     else if(nPos > (nAdd - 1))
1539     {
1540         pPrevPos1 = pPoints + (nPos - nAdd);
1541         aPrevFlag1 = *(pFlags + (nPos - nAdd));
1542     }
1543     else
1544         pPrevPos1 = 0L;
1545 }
1546 
1547 void Imp_PrepareCoorExport(sal_Int32& nX, sal_Int32& nY,
1548     const awt::Point* pPointArray, const awt::Point& rObjectPos,
1549     const awt::Size& rObjectSize, const SdXMLImExViewBox& mrViewBox,
1550     const bool bScale, const bool bTranslate)
1551 {
1552     nX = pPointArray->X - rObjectPos.X;
1553     nY = pPointArray->Y - rObjectPos.Y;
1554 
1555     if(bScale && rObjectSize.Width && rObjectSize.Height )
1556     {
1557         nX = (nX * mrViewBox.GetWidth()) / rObjectSize.Width;
1558         nY = (nY * mrViewBox.GetHeight()) / rObjectSize.Height;
1559     }
1560 
1561     if(bTranslate)
1562     {
1563         nX += mrViewBox.GetX();
1564         nY += mrViewBox.GetY();
1565     }
1566 }
1567 
1568 //#define TEST_QUADRATIC_CURVES
1569 #ifdef TEST_QUADRATIC_CURVES
1570 // To be able to test quadratic curve code: The code concerning to
1571 // bDoTestHere can be used (see below). Construct shapes which have their control
1572 // points on equal coordinates. When these are written, they can be
1573 // forced to create correct 'Q' and 'T' statements using this flag.
1574 // These may then be tested for import/exporting.
1575 static bool bDoTestHere(true);
1576 #endif // TEST_QUADRATIC_CURVES
1577 
1578 void SdXMLImExSvgDElement::AddPolygon(
1579     drawing::PointSequence* pPoints,
1580     drawing::FlagSequence* pFlags,
1581     const awt::Point& rObjectPos,
1582     const awt::Size& rObjectSize,
1583     bool bClosed, bool bRelative)
1584 {
1585     DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExSvgDElement(!)");
1586 
1587     sal_Int32 nCnt(pPoints->getLength());
1588 
1589     // #104076# Convert to string only when at last one point included
1590     if(nCnt > 0)
1591     {
1592         // append polygon to string
1593         OUString aNewString;
1594         sal_Unicode aLastCommand = ' ';
1595         awt::Point* pPointArray = pPoints->getArray();
1596 
1597         // are the flags used at all? If not forget about them
1598         if(pFlags)
1599         {
1600             sal_Int32 nFlagCnt(pFlags->getLength());
1601 
1602             if(nFlagCnt)
1603             {
1604                 bool bFlagsUsed(false);
1605                 drawing::PolygonFlags* pFlagArray = pFlags->getArray();
1606 
1607                 for(sal_Int32 a(0); !bFlagsUsed && a < nFlagCnt; a++)
1608                     if(drawing::PolygonFlags_NORMAL != *pFlagArray++)
1609                         bFlagsUsed = true;
1610 
1611                 if(!bFlagsUsed)
1612                     pFlags = 0L;
1613             }
1614             else
1615             {
1616                 pFlags = 0L;
1617             }
1618         }
1619 
1620         // object size and ViewBox size different?
1621         bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
1622             || rObjectSize.Height != mrViewBox.GetHeight());
1623         bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
1624 
1625         // #87202# rework of point reduction:
1626         // Test for Last point same -> closed, ignore last point. Take
1627         // some more circumstances in account when looking at curve segments.
1628         drawing::PolygonFlags* pFlagArray = (pFlags) ? pFlags->getArray() : 0L;
1629         if((pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y))
1630         {
1631             if(pFlags)
1632             {
1633                 // point needs to be ignored if point before it is
1634                 // NO control point. Else the last point is needed
1635                 // for exporting the last segment of the curve. That means
1636                 // that the last and the first point will be saved double,
1637                 // but SVG does not support a better solution here.
1638                 if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2)))
1639                 {
1640                     nCnt--;
1641                 }
1642             }
1643             else
1644             {
1645                 // no curve, ignore last point
1646                 nCnt--;
1647             }
1648         }
1649 
1650         // bezier poly, handle curves
1651         bool  bDidWriteStart(false);
1652 
1653         for(sal_Int32 a(0L); a < nCnt; a++)
1654         {
1655             if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray)
1656             {
1657                 bool bDidWriteAsCurve(false);
1658 
1659                 if(bDidWriteStart)
1660                 {
1661                     if(pFlags)
1662                     {
1663                         // real curve point, get previous to see if it's a control point
1664                         awt::Point* pPrevPos1;
1665                         drawing::PolygonFlags aPrevFlag1;
1666 
1667                         Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(),
1668                             pFlags->getArray(), a, nCnt, 1);
1669 
1670                         if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1)
1671                         {
1672                             // get previous2 to see if it's a control point, too
1673                             awt::Point* pPrevPos2;
1674                             drawing::PolygonFlags aPrevFlag2;
1675 
1676                             Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(),
1677                                 pFlags->getArray(), a, nCnt, 2);
1678 
1679                             if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2)
1680                             {
1681                                 // get previous3 to see if it's a curve point and if,
1682                                 // if it is fully symmetric or not
1683                                 awt::Point* pPrevPos3;
1684                                 drawing::PolygonFlags aPrevFlag3;
1685 
1686                                 Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(),
1687                                     pFlags->getArray(), a, nCnt, 3);
1688 
1689                                 if(pPrevPos3)
1690                                 {
1691                                     // prepare coordinates
1692                                     sal_Int32 nX, nY;
1693 
1694                                     Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
1695                                         mrViewBox, bScale, bTranslate);
1696 
1697                                     // #100617# test if this curve segment may be written as
1698                                     // a quadratic bezier
1699                                     // That's the case if both control points are in the same place
1700                                     // when they are prolonged to the common quadratic control point
1701                                     // Left:  P = (3P1 - P0) / 2
1702                                     // Right: P = (3P2 - P3) / 2
1703                                     bool bIsQuadratic(false);
1704                                     const bool bEnableSaveQuadratic(false);
1705 
1706                                     sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0));
1707                                     sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0));
1708                                     sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0));
1709                                     sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0));
1710                                     sal_Int32 nDist(0);
1711 
1712                                     if(nPX_L != nPX_R)
1713                                     {
1714                                         nDist += abs(nPX_L - nPX_R);
1715                                     }
1716 
1717                                     if(nPY_L != nPY_R)
1718                                     {
1719                                         nDist += abs(nPY_L - nPY_R);
1720                                     }
1721 
1722                                     if(nDist <= BORDER_INTEGERS_ARE_EQUAL)
1723                                     {
1724                                         if(bEnableSaveQuadratic)
1725                                         {
1726                                             bIsQuadratic = true;
1727                                         }
1728                                     }
1729 
1730 #ifdef TEST_QUADRATIC_CURVES
1731                                     if(bDoTestHere)
1732                                     {
1733                                         bIsQuadratic = false;
1734 
1735                                         if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y)
1736                                             bIsQuadratic = true;
1737                                     }
1738 #endif // TEST_QUADRATIC_CURVES
1739 
1740                                     if(bIsQuadratic)
1741                                     {
1742 #ifdef TEST_QUADRATIC_CURVES
1743                                         if(bDoTestHere)
1744                                         {
1745                                             bool bPrevPointIsSymmetric(false);
1746 
1747                                             if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1748                                             {
1749                                                 // get previous4 to see if it's a control point
1750                                                 awt::Point* pPrevPos4;
1751                                                 drawing::PolygonFlags aPrevFlag4;
1752 
1753                                                 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1754                                                     pFlags->getArray(), a, nCnt, 4);
1755 
1756                                                 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1757                                                 {
1758                                                     // okay, prevPos3 is symmetric (c2) and prevPos4
1759                                                     // is existing control point, the 's' statement can be used
1760                                                     bPrevPointIsSymmetric = true;
1761                                                 }
1762                                             }
1763 
1764                                             if(bPrevPointIsSymmetric)
1765                                             {
1766                                                 // write a shorthand/smooth quadratic curveto entry (T)
1767                                                 if(bRelative)
1768                                                 {
1769                                                     if(aLastCommand != sal_Unicode('t'))
1770                                                         aNewString += OUString(sal_Unicode('t'));
1771 
1772                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1773                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1774 
1775                                                     aLastCommand = sal_Unicode('t');
1776                                                 }
1777                                                 else
1778                                                 {
1779                                                     if(aLastCommand != sal_Unicode('T'))
1780                                                         aNewString += OUString(sal_Unicode('T'));
1781 
1782                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1783                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1784 
1785                                                     aLastCommand = sal_Unicode('T');
1786                                                 }
1787                                             }
1788                                             else
1789                                             {
1790                                                 // prepare coordinates
1791                                                 sal_Int32 nX1, nY1;
1792 
1793                                                 Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize,
1794                                                     mrViewBox, bScale, bTranslate);
1795 
1796                                                 // write a quadratic curveto entry (Q)
1797                                                 if(bRelative)
1798                                                 {
1799                                                     if(aLastCommand != sal_Unicode('q'))
1800                                                         aNewString += OUString(sal_Unicode('q'));
1801 
1802                                                     Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1803                                                     Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1804                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1805                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1806 
1807                                                     aLastCommand = sal_Unicode('q');
1808                                                 }
1809                                                 else
1810                                                 {
1811                                                     if(aLastCommand != sal_Unicode('Q'))
1812                                                         aNewString += OUString(sal_Unicode('Q'));
1813 
1814                                                     Imp_PutNumberCharWithSpace(aNewString, nX1);
1815                                                     Imp_PutNumberCharWithSpace(aNewString, nY1);
1816                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1817                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1818 
1819                                                     aLastCommand = sal_Unicode('Q');
1820                                                 }
1821                                             }
1822                                         }
1823                                         else
1824                                         {
1825 #endif // TEST_QUADRATIC_CURVES
1826                                             awt::Point aNewPoint(nPX_L, nPY_L);
1827                                             bool bPrevPointIsSmooth(false);
1828 
1829                                             if(drawing::PolygonFlags_SMOOTH == aPrevFlag3)
1830                                             {
1831                                                 // get previous4 to see if it's a control point
1832                                                 awt::Point* pPrevPos4;
1833                                                 drawing::PolygonFlags aPrevFlag4;
1834 
1835                                                 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1836                                                     pFlags->getArray(), a, nCnt, 4);
1837 
1838                                                 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1839                                                 {
1840                                                     // okay, prevPos3 is smooth (c1) and prevPos4
1841                                                     // is existing control point. Test if it's even symmetric
1842                                                     // and thus the 'T' statement may be used.
1843                                                     ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y);
1844                                                     ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y);
1845                                                     bool bSameLength(false);
1846                                                     bool bSameDirection(false);
1847 
1848                                                     // get vector values
1849                                                     Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
1850 
1851                                                     if(bSameLength && bSameDirection)
1852                                                         bPrevPointIsSmooth = true;
1853                                                 }
1854                                             }
1855 
1856                                             if(bPrevPointIsSmooth)
1857                                             {
1858                                                 // write a shorthand/smooth quadratic curveto entry (T)
1859                                                 if(bRelative)
1860                                                 {
1861                                                     if(aLastCommand != sal_Unicode('t'))
1862                                                         aNewString += String(sal_Unicode('t'));
1863 
1864                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1865                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1866 
1867                                                     aLastCommand = sal_Unicode('t');
1868                                                 }
1869                                                 else
1870                                                 {
1871                                                     if(aLastCommand != sal_Unicode('T'))
1872                                                         aNewString += String(sal_Unicode('T'));
1873 
1874                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1875                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1876 
1877                                                     aLastCommand = sal_Unicode('T');
1878                                                 }
1879                                             }
1880                                             else
1881                                             {
1882                                                 // prepare coordinates
1883                                                 sal_Int32 nX1, nY1;
1884 
1885                                                 Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize,
1886                                                     mrViewBox, bScale, bTranslate);
1887 
1888                                                 // write a quadratic curveto entry (Q)
1889                                                 if(bRelative)
1890                                                 {
1891                                                     if(aLastCommand != sal_Unicode('q'))
1892                                                         aNewString += String(sal_Unicode('q'));
1893 
1894                                                     Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1895                                                     Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1896                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1897                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1898 
1899                                                     aLastCommand = sal_Unicode('q');
1900                                                 }
1901                                                 else
1902                                                 {
1903                                                     if(aLastCommand != sal_Unicode('Q'))
1904                                                         aNewString += String(sal_Unicode('Q'));
1905 
1906                                                     Imp_PutNumberCharWithSpace(aNewString, nX1);
1907                                                     Imp_PutNumberCharWithSpace(aNewString, nY1);
1908                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1909                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1910 
1911                                                     aLastCommand = sal_Unicode('Q');
1912                                                 }
1913                                             }
1914 #ifdef TEST_QUADRATIC_CURVES
1915                                         }
1916 #endif // TEST_QUADRATIC_CURVES
1917                                     }
1918                                     else
1919                                     {
1920                                         bool bPrevPointIsSymmetric(false);
1921 
1922                                         if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1923                                         {
1924                                             // get previous4 to see if it's a control point
1925                                             awt::Point* pPrevPos4;
1926                                             drawing::PolygonFlags aPrevFlag4;
1927 
1928                                             Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1929                                                 pFlags->getArray(), a, nCnt, 4);
1930 
1931                                             if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1932                                             {
1933                                                 // okay, prevPos3 is symmetric (c2) and prevPos4
1934                                                 // is existing control point, the 's' statement can be used
1935                                                 bPrevPointIsSymmetric = true;
1936                                             }
1937                                         }
1938 
1939                                         // prepare coordinates
1940                                         sal_Int32 nX2, nY2;
1941 
1942                                         Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize,
1943                                             mrViewBox, bScale, bTranslate);
1944 
1945                                         if(bPrevPointIsSymmetric)
1946                                         {
1947                                             // write a shorthand/smooth curveto entry (S)
1948                                             if(bRelative)
1949                                             {
1950                                                 if(aLastCommand != sal_Unicode('s'))
1951                                                     aNewString += String(sal_Unicode('s'));
1952 
1953                                                 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1954                                                 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1955                                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1956                                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1957 
1958                                                 aLastCommand = sal_Unicode('s');
1959                                             }
1960                                             else
1961                                             {
1962                                                 if(aLastCommand != sal_Unicode('S'))
1963                                                     aNewString += String(sal_Unicode('S'));
1964 
1965                                                 Imp_PutNumberCharWithSpace(aNewString, nX2);
1966                                                 Imp_PutNumberCharWithSpace(aNewString, nY2);
1967                                                 Imp_PutNumberCharWithSpace(aNewString, nX);
1968                                                 Imp_PutNumberCharWithSpace(aNewString, nY);
1969 
1970                                                 aLastCommand = sal_Unicode('S');
1971                                             }
1972                                         }
1973                                         else
1974                                         {
1975                                             // prepare coordinates
1976                                             sal_Int32 nX1, nY1;
1977 
1978                                             Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize,
1979                                                 mrViewBox, bScale, bTranslate);
1980 
1981                                             // write a curveto entry (C)
1982                                             if(bRelative)
1983                                             {
1984                                                 if(aLastCommand != sal_Unicode('c'))
1985                                                     aNewString += String(sal_Unicode('c'));
1986 
1987                                                 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1988                                                 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1989                                                 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1990                                                 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1991                                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1992                                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1993 
1994                                                 aLastCommand = sal_Unicode('c');
1995                                             }
1996                                             else
1997                                             {
1998                                                 if(aLastCommand != sal_Unicode('C'))
1999                                                     aNewString += String(sal_Unicode('C'));
2000 
2001                                                 Imp_PutNumberCharWithSpace(aNewString, nX1);
2002                                                 Imp_PutNumberCharWithSpace(aNewString, nY1);
2003                                                 Imp_PutNumberCharWithSpace(aNewString, nX2);
2004                                                 Imp_PutNumberCharWithSpace(aNewString, nY2);
2005                                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2006                                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2007 
2008                                                 aLastCommand = sal_Unicode('C');
2009                                             }
2010                                         }
2011                                     }
2012 
2013                                     // remember that current point IS written
2014                                     bDidWriteAsCurve = true;
2015 
2016                                     // remember new last position
2017                                     mnLastX = nX;
2018                                     mnLastY = nY;
2019                                 }
2020                             }
2021                         }
2022                     }
2023                 }
2024 
2025                 if(!bDidWriteAsCurve)
2026                 {
2027                     // current point not yet written, prepare coordinates
2028                     sal_Int32 nX, nY;
2029 
2030                     Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
2031                         mrViewBox, bScale, bTranslate);
2032 
2033                     if(bDidWriteStart)
2034                     {
2035                         // write as normal point
2036                         if(mnLastX == nX)
2037                         {
2038                             if(bRelative)
2039                             {
2040                                 if(aLastCommand != sal_Unicode('v'))
2041                                     aNewString += String(sal_Unicode('v'));
2042 
2043                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2044 
2045                                 aLastCommand = sal_Unicode('v');
2046                             }
2047                             else
2048                             {
2049                                 if(aLastCommand != sal_Unicode('V'))
2050                                     aNewString += String(sal_Unicode('V'));
2051 
2052                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2053 
2054                                 aLastCommand = sal_Unicode('V');
2055                             }
2056                         }
2057                         else if(mnLastY == nY)
2058                         {
2059                             if(bRelative)
2060                             {
2061                                 if(aLastCommand != sal_Unicode('h'))
2062                                     aNewString += String(sal_Unicode('h'));
2063 
2064                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2065 
2066                                 aLastCommand = sal_Unicode('h');
2067                             }
2068                             else
2069                             {
2070                                 if(aLastCommand != sal_Unicode('H'))
2071                                     aNewString += String(sal_Unicode('H'));
2072 
2073                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2074 
2075                                 aLastCommand = sal_Unicode('H');
2076                             }
2077                         }
2078                         else
2079                         {
2080                             if(bRelative)
2081                             {
2082                                 if(aLastCommand != sal_Unicode('l'))
2083                                     aNewString += String(sal_Unicode('l'));
2084 
2085                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2086                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2087 
2088                                 aLastCommand = sal_Unicode('l');
2089                             }
2090                             else
2091                             {
2092                                 if(aLastCommand != sal_Unicode('L'))
2093                                     aNewString += String(sal_Unicode('L'));
2094 
2095                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2096                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2097 
2098                                 aLastCommand = sal_Unicode('L');
2099                             }
2100                         }
2101                     }
2102                     else
2103                     {
2104                         // write as start point
2105                         if(bRelative)
2106                         {
2107                             aNewString += String(sal_Unicode('m'));
2108 
2109                             Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2110                             Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2111 
2112                             aLastCommand = sal_Unicode('l');
2113                         }
2114                         else
2115                         {
2116                             aNewString += String(sal_Unicode('M'));
2117 
2118                             Imp_PutNumberCharWithSpace(aNewString, nX);
2119                             Imp_PutNumberCharWithSpace(aNewString, nY);
2120 
2121                             aLastCommand = sal_Unicode('L');
2122                         }
2123 
2124                         // remember start written
2125                         bDidWriteStart = true;
2126                     }
2127 
2128                     // remember new last position
2129                     mnLastX = nX;
2130                     mnLastY = nY;
2131                 }
2132             }
2133 
2134             // next point
2135             pPointArray++;
2136             pFlagArray++;
2137         }
2138 
2139         // close path if closed poly
2140         if(bClosed)
2141         {
2142             if(bRelative)
2143                 aNewString += String(sal_Unicode('z'));
2144             else
2145                 aNewString += String(sal_Unicode('Z'));
2146         }
2147 
2148         // append new string
2149         msString += aNewString;
2150     }
2151 }
2152 
2153 // #100617# Linear double reader
2154 double Imp_ImportDoubleAndSpaces(
2155     double fRetval, const OUString& rStr, sal_Int32& rPos,
2156     const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2157 {
2158     fRetval = Imp_GetDoubleChar(rStr, rPos, nLen, rConv, fRetval);
2159     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2160     return fRetval;
2161 }
2162 
2163 // #100617# Allow to read doubles, too. This will need to be changed to
2164 // the usage of Imp_ImportDoubleAndSpaces(...). For now, this is sufficient
2165 // since the interface cannot transport doubles.
2166 sal_Int32 Imp_ImportNumberAndSpaces(
2167     sal_Int32 nRetval, const OUString& rStr, sal_Int32& rPos,
2168     const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2169 {
2170     nRetval = FRound(Imp_ImportDoubleAndSpaces(double(nRetval), rStr, rPos, nLen, rConv));
2171     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2172     return nRetval;
2173 }
2174 
2175 void Imp_PrepareCoorImport(sal_Int32& nX, sal_Int32& nY,
2176     const awt::Point& rObjectPos, const awt::Size& rObjectSize,
2177     const SdXMLImExViewBox& rViewBox, const bool bScale, const bool bTranslate)
2178 {
2179     if(bTranslate)
2180     {
2181         nX -= rViewBox.GetX();
2182         nY -= rViewBox.GetY();
2183     }
2184 
2185     if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight())
2186     {
2187         nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
2188         nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
2189     }
2190 
2191     nX += rObjectPos.X;
2192     nY += rObjectPos.Y;
2193 }
2194 
2195 void Imp_AddExportPoints(sal_Int32 nX, sal_Int32 nY,
2196     awt::Point* pPoints, drawing::PolygonFlags* pFlags,
2197     const sal_Int32 nInnerIndex,
2198     drawing::PolygonFlags eFlag)
2199 {
2200     if(pPoints)
2201         pPoints[nInnerIndex] = awt::Point( nX, nY );
2202 
2203     if(pFlags)
2204         pFlags[nInnerIndex] = eFlag;
2205 }
2206 
2207 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection)
2208 {
2209     const sal_Int32 nLen1(FRound(aVec1.getLength()));
2210     const sal_Int32 nLen2(FRound(aVec2.getLength()));
2211     aVec1.normalize();
2212     aVec2.normalize();
2213     aVec1 += aVec2;
2214     const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0)));
2215 
2216     bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL);
2217     bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL);
2218 }
2219 
2220 void Imp_CorrectPolygonFlag(const sal_uInt32 nInnerIndex, const awt::Point* const pInnerSequence,
2221     drawing::PolygonFlags* const pInnerFlags, const sal_Int32 nX1, const sal_Int32 nY1)
2222 {
2223     if(nInnerIndex)
2224     {
2225         const awt::Point aPPrev1 = pInnerSequence[nInnerIndex - 1];
2226 
2227         if(nInnerIndex > 1)
2228         {
2229             const awt::Point aPPrev2 = pInnerSequence[nInnerIndex - 2];
2230             const drawing::PolygonFlags aFPrev2 = pInnerFlags[nInnerIndex - 2];
2231             ::basegfx::B2DVector aVec1(aPPrev2.X - aPPrev1.X, aPPrev2.Y - aPPrev1.Y);
2232             ::basegfx::B2DVector aVec2(nX1 - aPPrev1.X, nY1 - aPPrev1.Y);
2233             bool bSameLength(false);
2234             bool bSameDirection(false);
2235 
2236             // get vector values
2237             Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
2238 
2239             if(drawing::PolygonFlags_CONTROL == aFPrev2)
2240             {
2241                 // point before is a control point
2242                 if(bSameDirection)
2243                 {
2244                     if(bSameLength)
2245                     {
2246                         // set to PolygonFlags_SYMMETRIC
2247                         pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2248                     }
2249                     else
2250                     {
2251                         // set to PolygonFlags_SMOOTH
2252                         pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2253                     }
2254                 }
2255                 else
2256                 {
2257                     // set to PolygonFlags_NORMAL
2258                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2259                 }
2260             }
2261             else
2262             {
2263                 // point before is a simple curve point
2264                 if(bSameDirection)
2265                 {
2266                     // set to PolygonFlags_SMOOTH
2267                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2268                 }
2269                 else
2270                 {
2271                     // set to PolygonFlags_NORMAL
2272                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2273                 }
2274             }
2275         }
2276         else
2277         {
2278             // no point before starpoint, set type to PolygonFlags_NORMAL
2279             pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2280         }
2281     }
2282 }
2283 
2284 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew,
2285     const SdXMLImExViewBox& rViewBox,
2286     const awt::Point& rObjectPos,
2287     const awt::Size& rObjectSize,
2288     const SvXMLUnitConverter& rConv)
2289 :   msString( rNew ),
2290     mrViewBox( rViewBox ),
2291     mbIsClosed( false ),
2292     mbIsCurve( false ),
2293     mnLastX( 0L ),
2294     mnLastY( 0L ),
2295     maPoly( 0L ),
2296     maFlag( 0L )
2297 {
2298     // convert string to polygon
2299     const OUString aStr(msString.getStr(), msString.getLength());
2300     const sal_Int32 nLen(aStr.getLength());
2301     sal_Int32 nPos(0);
2302     sal_Int32 nNumPolys(0L);
2303     bool bEllipticalArc(false);
2304 
2305     // object size and ViewBox size different?
2306     bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
2307         || rObjectSize.Height != mrViewBox.GetHeight());
2308     bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
2309 
2310     // first loop: count polys and get flags
2311     Imp_SkipSpaces(aStr, nPos, nLen);
2312 
2313     while(nPos < nLen)
2314     {
2315         switch(aStr[nPos++])
2316         {
2317             case 'Z' :
2318             case 'z' :
2319             {
2320                 break;
2321             }
2322             case 'M' :
2323             case 'm' :
2324             {
2325                 nNumPolys++;
2326                 break;
2327             }
2328             case 'S' :
2329             case 's' :
2330             case 'C' :
2331             case 'c' :
2332             case 'Q' :
2333             case 'q' :
2334             case 'T' :
2335             case 't' :
2336             {
2337                 mbIsCurve = true;
2338                 break;
2339             }
2340             case 'L' :
2341             case 'l' :
2342             case 'H' :
2343             case 'h' :
2344             case 'V' :
2345             case 'v' :
2346             {
2347                 // normal, interpreted values. All okay.
2348                 break;
2349             }
2350             case 'A' :
2351             case 'a' :
2352             {
2353                 // Not yet interpreted value.
2354                 bEllipticalArc = true;
2355                 break;
2356             }
2357         }
2358     }
2359 
2360     DBG_ASSERT(!bEllipticalArc, "XMLIMP: non-interpreted tags in svg:d element!");
2361 
2362     if(nNumPolys)
2363     {
2364         // alloc arrays
2365         maPoly.realloc(nNumPolys);
2366         if(IsCurve())
2367             maFlag.realloc(nNumPolys);
2368 
2369         // get outer sequences
2370         drawing::PointSequence* pOuterSequence = maPoly.getArray();
2371         drawing::FlagSequence* pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2372 
2373         // prepare new loop, count
2374         sal_uInt32 nPointCount(0L);
2375         nPos = 0;
2376         Imp_SkipSpaces(aStr, nPos, nLen);
2377 
2378         // #104076# reset closed flag for next to be started polygon
2379         mbIsClosed = false;
2380 
2381         while(nPos < nLen)
2382         {
2383             switch(aStr[nPos])
2384             {
2385                 case 'z' :
2386                 case 'Z' :
2387                 {
2388                     nPos++;
2389                     Imp_SkipSpaces(aStr, nPos, nLen);
2390 
2391                     // #104076# remember closed state of current polygon
2392                     mbIsClosed = true;
2393 
2394                     break;
2395                 }
2396                 case 'm' :
2397                 case 'M' :
2398                 {
2399                     // new poly starts, end-process current poly
2400                     if(nPointCount)
2401                     {
2402                         // #104076# If this partial polygon is closed, use one more point
2403                         // to represent that
2404                         if(mbIsClosed)
2405                         {
2406                             nPointCount++;
2407                         }
2408 
2409                         pOuterSequence->realloc(nPointCount);
2410                         pOuterSequence++;
2411 
2412                         if(pOuterFlags)
2413                         {
2414                             pOuterFlags->realloc(nPointCount);
2415                             pOuterFlags++;
2416                         }
2417 
2418                         // reset point count for next polygon
2419                         nPointCount = 0L;
2420                     }
2421 
2422                     // #104076# reset closed flag for next to be started polygon
2423                     mbIsClosed = false;
2424 
2425                     // NO break, continue in next case
2426                 }
2427                 case 'L' :
2428                 case 'l' :
2429                 {
2430                     nPos++;
2431                     Imp_SkipSpaces(aStr, nPos, nLen);
2432 
2433                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2434                     {
2435                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2436                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2437                         nPointCount++;
2438                     }
2439                     break;
2440                 }
2441                 case 'H' :
2442                 case 'h' :
2443                 case 'V' :
2444                 case 'v' :
2445                 {
2446                     nPos++;
2447                     Imp_SkipSpaces(aStr, nPos, nLen);
2448 
2449                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2450                     {
2451                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2452                         nPointCount++;
2453                     }
2454                     break;
2455                 }
2456                 case 'S' :
2457                 case 's' :
2458                 {
2459                     nPos++;
2460                     Imp_SkipSpaces(aStr, nPos, nLen);
2461 
2462                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2463                     {
2464                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2465                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2466                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2467                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2468                         nPointCount += 3;
2469                     }
2470                     break;
2471                 }
2472                 case 'C' :
2473                 case 'c' :
2474                 {
2475                     nPos++;
2476                     Imp_SkipSpaces(aStr, nPos, nLen);
2477 
2478                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2479                     {
2480                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2481                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2482                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2483                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2484                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2485                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2486                         nPointCount += 3;
2487                     }
2488                     break;
2489                 }
2490 
2491                 // #100617# quadratic beziers, supported as cubic ones
2492                 case 'Q' :
2493                 case 'q' :
2494                 {
2495                     nPos++;
2496                     Imp_SkipSpaces(aStr, nPos, nLen);
2497 
2498                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2499                     {
2500                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2501                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2502                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2503                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2504 
2505                         // use three points since quadratic is imported as cubic
2506                         nPointCount += 3;
2507                     }
2508                     break;
2509                 }
2510 
2511                 // #100617# relative quadratic beziers, supported as cubic ones
2512                 case 'T' :
2513                 case 't' :
2514                 {
2515                     nPos++;
2516                     Imp_SkipSpaces(aStr, nPos, nLen);
2517 
2518                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2519                     {
2520                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2521                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2522 
2523                         // use three points since quadratic is imported as cubic
2524                         nPointCount += 3;
2525                     }
2526                     break;
2527                 }
2528 
2529                 // #100617# not yet supported: elliptical arc
2530                 case 'A' :
2531                 case 'a' :
2532                 {
2533                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2534                     nPos++;
2535                     Imp_SkipSpaces(aStr, nPos, nLen);
2536 
2537                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2538                     {
2539                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2540                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2541                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2542                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2543                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2544                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2545                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2546                     }
2547                     break;
2548                 }
2549 
2550                 default:
2551                 {
2552                     nPos++;
2553                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
2554                     break;
2555                 }
2556             }
2557         }
2558 
2559         // alloc last poly (when points used)
2560         if(nPointCount)
2561         {
2562             // #104076# If this partial polygon is closed, use one more point
2563             // to represent that
2564             if(mbIsClosed)
2565             {
2566                 nPointCount++;
2567             }
2568 
2569             pOuterSequence->realloc(nPointCount);
2570             pOuterSequence++;
2571 
2572             if(pOuterFlags)
2573             {
2574                 pOuterFlags->realloc(nPointCount);
2575                 pOuterFlags++;
2576             }
2577         }
2578 
2579         // set pointers back
2580         pOuterSequence = maPoly.getArray();
2581         pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2582         awt::Point* pNotSoInnerSequence = 0L;
2583         drawing::PolygonFlags* pNotSoInnerFlags = 0L;
2584         sal_uInt32 nInnerIndex(0L);
2585 
2586         // prepare new loop, read points
2587         nPos = 0;
2588         Imp_SkipSpaces(aStr, nPos, nLen);
2589 
2590         // #104076# reset closed flag for next to be started polygon
2591         mbIsClosed = false;
2592 
2593         while(nPos < nLen)
2594         {
2595             bool bRelative(false);
2596 
2597             switch(aStr[nPos])
2598             {
2599                 case 'z' :
2600                 case 'Z' :
2601                 {
2602                     nPos++;
2603                     Imp_SkipSpaces(aStr, nPos, nLen);
2604 
2605                     // #104076# remember closed state of current polygon
2606                     mbIsClosed = true;
2607 
2608                     // closed: add first point again
2609                     // sal_Int32 nX(pInnerSequence[0].X);
2610                     // sal_Int32 nY(pInnerSequence[0].Y);
2611                     // Imp_AddExportPoints(nX, nY, pInnerSequence, pInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2612 
2613                     break;
2614                 }
2615 
2616                 case 'm' :
2617                 {
2618                     bRelative = true;
2619                 }
2620                 case 'M' :
2621                 {
2622                     // #104076# end-process current poly
2623                     if(mbIsClosed)
2624                     {
2625                         if(pNotSoInnerSequence)
2626                         {
2627                             // closed: add first point again
2628                             sal_Int32 nX(pNotSoInnerSequence[0].X);
2629                             sal_Int32 nY(pNotSoInnerSequence[0].Y);
2630                             Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2631                         }
2632 
2633                         // reset closed flag for next to be started polygon
2634                         mbIsClosed = false;
2635                     }
2636 
2637                     // next poly
2638                     pNotSoInnerSequence = pOuterSequence->getArray();
2639                     pOuterSequence++;
2640 
2641                     if(pOuterFlags)
2642                     {
2643                         pNotSoInnerFlags = pOuterFlags->getArray();
2644                         pOuterFlags++;
2645                     }
2646 
2647                     nInnerIndex = 0L;
2648 
2649                     nPos++;
2650                     Imp_SkipSpaces(aStr, nPos, nLen);
2651 
2652                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2653                     {
2654                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2655                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2656 
2657                         if(bRelative)
2658                         {
2659                             nX += mnLastX;
2660                             nY += mnLastY;
2661                         }
2662 
2663                         // set last position
2664                         mnLastX = nX;
2665                         mnLastY = nY;
2666 
2667                         // calc transform and add point and flag
2668                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2669                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2670                     }
2671                     break;
2672                 }
2673 
2674                 case 'l' :
2675                 {
2676                     bRelative = true;
2677                 }
2678                 case 'L' :
2679                 {
2680                     nPos++;
2681                     Imp_SkipSpaces(aStr, nPos, nLen);
2682 
2683                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2684                     {
2685                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2686                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2687 
2688                         if(bRelative)
2689                         {
2690                             nX += mnLastX;
2691                             nY += mnLastY;
2692                         }
2693 
2694                         // set last position
2695                         mnLastX = nX;
2696                         mnLastY = nY;
2697 
2698                         // calc transform and add point and flag
2699                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2700                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2701                     }
2702                     break;
2703                 }
2704 
2705                 case 'h' :
2706                 {
2707                     bRelative = true;
2708                 }
2709                 case 'H' :
2710                 {
2711                     nPos++;
2712                     Imp_SkipSpaces(aStr, nPos, nLen);
2713 
2714                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2715                     {
2716                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2717                         sal_Int32 nY(mnLastY);
2718 
2719                         if(bRelative)
2720                             nX += mnLastX;
2721 
2722                         // set last position
2723                         mnLastX = nX;
2724 
2725                         // calc transform and add point and flag
2726                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2727                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2728                     }
2729                     break;
2730                 }
2731 
2732                 case 'v' :
2733                 {
2734                     bRelative = true;
2735                 }
2736                 case 'V' :
2737                 {
2738                     nPos++;
2739                     Imp_SkipSpaces(aStr, nPos, nLen);
2740 
2741                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2742                     {
2743                         sal_Int32 nX(mnLastX);
2744                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2745 
2746                         if(bRelative)
2747                             nY += mnLastY;
2748 
2749                         // set last position
2750                         mnLastY = nY;
2751 
2752                         // calc transform and add point and flag
2753                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2754                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2755                     }
2756                     break;
2757                 }
2758 
2759                 case 's' :
2760                 {
2761                     bRelative = true;
2762                 }
2763                 case 'S' :
2764                 {
2765                     nPos++;
2766                     Imp_SkipSpaces(aStr, nPos, nLen);
2767 
2768                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2769                     {
2770                         sal_Int32 nX1;
2771                         sal_Int32 nY1;
2772                         sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2773                         sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2774                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2775                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2776 
2777                         if(bRelative)
2778                         {
2779                             nX2 += mnLastX;
2780                             nY2 += mnLastY;
2781                             nX += mnLastX;
2782                             nY += mnLastY;
2783                         }
2784 
2785                         // set last position
2786                         mnLastX = nX;
2787                         mnLastY = nY;
2788 
2789                         // calc transform for new points
2790                         Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2791                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2792 
2793                         // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2794                         // and the Point X1,Y1 can be constructed by mirroring the point before it.
2795                         nX1 = nX2;
2796                         nY1 = nY2;
2797                         if(nInnerIndex)
2798                         {
2799                             awt::Point aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2800 
2801                             if(nInnerIndex > 1)
2802                             {
2803                                 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2804                                 nX1 = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2805                                 nY1 = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2806                             }
2807 
2808                             // set curve point to symmetric
2809                             pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2810                         }
2811 
2812                         // add calculated control point
2813                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2814 
2815                         // add new points and set flags
2816                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2817                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2818                     }
2819                     break;
2820                 }
2821 
2822                 case 'c' :
2823                 {
2824                     bRelative = true;
2825                 }
2826                 case 'C' :
2827                 {
2828                     nPos++;
2829                     Imp_SkipSpaces(aStr, nPos, nLen);
2830 
2831                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2832                     {
2833                         sal_Int32 nX1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2834                         sal_Int32 nY1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2835                         sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2836                         sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2837                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2838                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2839 
2840                         if(bRelative)
2841                         {
2842                             nX1 += mnLastX;
2843                             nY1 += mnLastY;
2844                             nX2 += mnLastX;
2845                             nY2 += mnLastY;
2846                             nX += mnLastX;
2847                             nY += mnLastY;
2848                         }
2849 
2850                         // set last position
2851                         mnLastX = nX;
2852                         mnLastY = nY;
2853 
2854                         // calc transform for new points
2855                         Imp_PrepareCoorImport(nX1, nY1, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2856                         Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2857                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2858 
2859                         // correct polygon flag for previous point
2860                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2861 
2862                         // add new points and set flags
2863                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2864                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2865                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2866                     }
2867                     break;
2868                 }
2869 
2870                 // #100617# quadratic beziers are imported as cubic
2871                 case 'q' :
2872                 {
2873                     bRelative = true;
2874                 }
2875                 case 'Q' :
2876                 {
2877                     nPos++;
2878                     Imp_SkipSpaces(aStr, nPos, nLen);
2879 
2880                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2881                     {
2882                         sal_Int32 nXX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2883                         sal_Int32 nYY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2884                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2885                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2886 
2887                         if(bRelative)
2888                         {
2889                             nXX += mnLastX;
2890                             nYY += mnLastY;
2891                             nX += mnLastX;
2892                             nY += mnLastY;
2893                         }
2894 
2895                         // set last position
2896                         mnLastX = nX;
2897                         mnLastY = nY;
2898 
2899                         // calc transform for new points
2900                         Imp_PrepareCoorImport(nXX, nYY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2901                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2902 
2903                         // calculate X1,X2
2904                         awt::Point aPPrev1 = (nInnerIndex) ? pNotSoInnerSequence[nInnerIndex-1] : pNotSoInnerSequence[0];
2905                         sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2906                         sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2907                         sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2908                         sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2909 
2910                         // correct polygon flag for previous point
2911                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2912 
2913                         // add new points and set flags
2914                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2915                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2916                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2917                     }
2918                     break;
2919                 }
2920 
2921                 // #100617# relative quadratic beziers are imported as cubic
2922                 case 't' :
2923                 {
2924                     bRelative = true;
2925                 }
2926                 case 'T' :
2927                 {
2928                     nPos++;
2929                     Imp_SkipSpaces(aStr, nPos, nLen);
2930 
2931                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2932                     {
2933                         sal_Int32 nXX;
2934                         sal_Int32 nYY;
2935                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2936                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2937 
2938                         if(bRelative)
2939                         {
2940                             nX += mnLastX;
2941                             nY += mnLastY;
2942                         }
2943 
2944                         // set last position
2945                         mnLastX = nX;
2946                         mnLastY = nY;
2947 
2948                         // calc transform for new points
2949                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2950 
2951                         // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2952                         // and the Point X1,Y1 can be constructed by mirroring the point before it.
2953                         nXX = nX;
2954                         nYY = nY;
2955                         awt::Point aPPrev1 = pNotSoInnerSequence[0];
2956 
2957                         if(nInnerIndex)
2958                         {
2959                             aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2960 
2961                             if(nInnerIndex > 1)
2962                             {
2963                                 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2964                                 nXX = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2965                                 nYY = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2966                             }
2967 
2968                             // set curve point to smooth here, since length
2969                             // is changed and thus only c1 can be used.
2970                             pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2971                         }
2972 
2973                         // calculate X1,X2
2974                         sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2975                         sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2976                         sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2977                         sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2978 
2979                         // correct polygon flag for previous point
2980                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2981 
2982                         // add new points and set flags
2983                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2984                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2985                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2986                     }
2987                     break;
2988                 }
2989 
2990                 // #100617# not yet supported: elliptical arc
2991                 case 'A' :
2992                 case 'a' :
2993                 {
2994                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2995                     nPos++;
2996                     Imp_SkipSpaces(aStr, nPos, nLen);
2997 
2998                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2999                     {
3000                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3001                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3002                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3003                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3004                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3005                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3006                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3007                     }
3008                     break;
3009                 }
3010 
3011                 default:
3012                 {
3013                     nPos++;
3014                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
3015                     break;
3016                 }
3017             }
3018         }
3019 
3020         // #104076# end-process closed state of last poly
3021         if(mbIsClosed)
3022         {
3023             if(pNotSoInnerSequence)
3024             {
3025                 // closed: add first point again
3026                 sal_Int32 nX(pNotSoInnerSequence[0].X);
3027                 sal_Int32 nY(pNotSoInnerSequence[0].Y);
3028                 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
3029             }
3030         }
3031 
3032         // #87202# If it's a curve and it's closed the last point maybe too much
3033         // and just exported since SVG does not allow special handling of same
3034         // start and end point, remove this last point.
3035         // Evtl. correct the last curve flags, too.
3036         if(IsCurve() && IsClosed())
3037         {
3038             // make one more loop over the PolyPolygon
3039             pOuterSequence = maPoly.getArray();
3040             pOuterFlags = maFlag.getArray();
3041             sal_Int32 nOuterCnt(maPoly.getLength());
3042 
3043             for(sal_Int32 a(0); a < nOuterCnt; a++)
3044             {
3045                 // get Polygon pointers
3046                 awt::Point* pInnerSequence = pOuterSequence->getArray();
3047                 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
3048                 sal_Int32 nInnerCnt(pOuterSequence->getLength());
3049 
3050                 while( nInnerCnt >= 2
3051                     && ((pInnerSequence + (nInnerCnt - 2))->X == (pInnerSequence + (nInnerCnt - 1))->X)
3052                     && ((pInnerSequence + (nInnerCnt - 2))->Y == (pInnerSequence + (nInnerCnt - 1))->Y)
3053                     && drawing::PolygonFlags_CONTROL != *(pInnerFlags + (nInnerCnt - 2)))
3054                 {
3055                     // remove last point from array
3056                     pOuterSequence->realloc(nInnerCnt - 1);
3057                     pOuterFlags->realloc(nInnerCnt - 1);
3058 
3059                     // get new pointers
3060                     pInnerSequence = pOuterSequence->getArray();
3061                     pInnerFlags = pOuterFlags->getArray();
3062                     nInnerCnt = pOuterSequence->getLength();
3063                 }
3064 
3065                 // now evtl. correct the last curve flags
3066                 if(nInnerCnt >= 4)
3067                 {
3068                     if( pInnerSequence->X == (pInnerSequence + (nInnerCnt - 1))->X
3069                         && pInnerSequence->Y == (pInnerSequence + (nInnerCnt - 1))->Y
3070                         && drawing::PolygonFlags_CONTROL == *(pInnerFlags + 1)
3071                         && drawing::PolygonFlags_CONTROL == *(pInnerFlags + (nInnerCnt - 2)))
3072                     {
3073                         awt::Point aPrev = *(pInnerSequence + (nInnerCnt - 2));
3074                         awt::Point aCurr = *pInnerSequence;
3075                         awt::Point aNext = *(pInnerSequence + 1);
3076                         ::basegfx::B2DVector aVec1(aPrev.X - aCurr.X, aPrev.Y - aCurr.Y);
3077                         ::basegfx::B2DVector aVec2(aNext.X - aCurr.X, aNext.Y - aCurr.Y);
3078                         bool bSameLength(false);
3079                         bool bSameDirection(false);
3080 
3081                         // get vector values
3082                         Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
3083 
3084                         // set correct flag value
3085                         if(bSameDirection)
3086                         {
3087                             if(bSameLength)
3088                             {
3089                                 // set to PolygonFlags_SYMMETRIC
3090                                 *pInnerFlags = drawing::PolygonFlags_SYMMETRIC;
3091                                 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SYMMETRIC;
3092                             }
3093                             else
3094                             {
3095                                 // set to PolygonFlags_SMOOTH
3096                                 *pInnerFlags = drawing::PolygonFlags_SMOOTH;
3097                                 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SMOOTH;
3098                             }
3099                         }
3100                         else
3101                         {
3102                             // set to PolygonFlags_NORMAL
3103                             *pInnerFlags = drawing::PolygonFlags_NORMAL;
3104                             *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_NORMAL;
3105                         }
3106                     }
3107                 }
3108 
3109                 // switch to next Polygon
3110                 pOuterSequence++;
3111                 pOuterFlags++;
3112             }
3113         }
3114     }
3115 }
3116 
3117 // eof
3118