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