xref: /AOO41X/main/xmloff/source/draw/xexptran.cxx (revision ff0525f24f03981d56b7579b645949f111420994)
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 
1626         // #121090# only reduce double start/end points if polygon *is* closed
1627         if(bClosed && (pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y))
1628         {
1629             if(pFlags)
1630             {
1631                 // point needs to be ignored if point before it is
1632                 // NO control point. Else the last point is needed
1633                 // for exporting the last segment of the curve. That means
1634                 // that the last and the first point will be saved double,
1635                 // but SVG does not support a better solution here.
1636                 if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2)))
1637                 {
1638                     nCnt--;
1639                 }
1640             }
1641             else
1642             {
1643                 // no curve, ignore last point
1644                 nCnt--;
1645             }
1646         }
1647 
1648         // bezier poly, handle curves
1649         bool  bDidWriteStart(false);
1650 
1651         for(sal_Int32 a(0L); a < nCnt; a++)
1652         {
1653             if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray)
1654             {
1655                 bool bDidWriteAsCurve(false);
1656 
1657                 if(bDidWriteStart)
1658                 {
1659                     if(pFlags)
1660                     {
1661                         // real curve point, get previous to see if it's a control point
1662                         awt::Point* pPrevPos1;
1663                         drawing::PolygonFlags aPrevFlag1;
1664 
1665                         Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(),
1666                             pFlags->getArray(), a, nCnt, 1);
1667 
1668                         if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1)
1669                         {
1670                             // get previous2 to see if it's a control point, too
1671                             awt::Point* pPrevPos2;
1672                             drawing::PolygonFlags aPrevFlag2;
1673 
1674                             Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(),
1675                                 pFlags->getArray(), a, nCnt, 2);
1676 
1677                             if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2)
1678                             {
1679                                 // get previous3 to see if it's a curve point and if,
1680                                 // if it is fully symmetric or not
1681                                 awt::Point* pPrevPos3;
1682                                 drawing::PolygonFlags aPrevFlag3;
1683 
1684                                 Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(),
1685                                     pFlags->getArray(), a, nCnt, 3);
1686 
1687                                 if(pPrevPos3)
1688                                 {
1689                                     // prepare coordinates
1690                                     sal_Int32 nX, nY;
1691 
1692                                     Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
1693                                         mrViewBox, bScale, bTranslate);
1694 
1695                                     // #100617# test if this curve segment may be written as
1696                                     // a quadratic bezier
1697                                     // That's the case if both control points are in the same place
1698                                     // when they are prolonged to the common quadratic control point
1699                                     // Left:  P = (3P1 - P0) / 2
1700                                     // Right: P = (3P2 - P3) / 2
1701                                     bool bIsQuadratic(false);
1702                                     const bool bEnableSaveQuadratic(false);
1703 
1704                                     sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0));
1705                                     sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0));
1706                                     sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0));
1707                                     sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0));
1708                                     sal_Int32 nDist(0);
1709 
1710                                     if(nPX_L != nPX_R)
1711                                     {
1712                                         nDist += abs(nPX_L - nPX_R);
1713                                     }
1714 
1715                                     if(nPY_L != nPY_R)
1716                                     {
1717                                         nDist += abs(nPY_L - nPY_R);
1718                                     }
1719 
1720                                     if(nDist <= BORDER_INTEGERS_ARE_EQUAL)
1721                                     {
1722                                         if(bEnableSaveQuadratic)
1723                                         {
1724                                             bIsQuadratic = true;
1725                                         }
1726                                     }
1727 
1728 #ifdef TEST_QUADRATIC_CURVES
1729                                     if(bDoTestHere)
1730                                     {
1731                                         bIsQuadratic = false;
1732 
1733                                         if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y)
1734                                             bIsQuadratic = true;
1735                                     }
1736 #endif // TEST_QUADRATIC_CURVES
1737 
1738                                     if(bIsQuadratic)
1739                                     {
1740 #ifdef TEST_QUADRATIC_CURVES
1741                                         if(bDoTestHere)
1742                                         {
1743                                             bool bPrevPointIsSymmetric(false);
1744 
1745                                             if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1746                                             {
1747                                                 // get previous4 to see if it's a control point
1748                                                 awt::Point* pPrevPos4;
1749                                                 drawing::PolygonFlags aPrevFlag4;
1750 
1751                                                 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1752                                                     pFlags->getArray(), a, nCnt, 4);
1753 
1754                                                 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1755                                                 {
1756                                                     // okay, prevPos3 is symmetric (c2) and prevPos4
1757                                                     // is existing control point, the 's' statement can be used
1758                                                     bPrevPointIsSymmetric = true;
1759                                                 }
1760                                             }
1761 
1762                                             if(bPrevPointIsSymmetric)
1763                                             {
1764                                                 // write a shorthand/smooth quadratic curveto entry (T)
1765                                                 if(bRelative)
1766                                                 {
1767                                                     if(aLastCommand != sal_Unicode('t'))
1768                                                         aNewString += OUString(sal_Unicode('t'));
1769 
1770                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1771                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1772 
1773                                                     aLastCommand = sal_Unicode('t');
1774                                                 }
1775                                                 else
1776                                                 {
1777                                                     if(aLastCommand != sal_Unicode('T'))
1778                                                         aNewString += OUString(sal_Unicode('T'));
1779 
1780                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1781                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1782 
1783                                                     aLastCommand = sal_Unicode('T');
1784                                                 }
1785                                             }
1786                                             else
1787                                             {
1788                                                 // prepare coordinates
1789                                                 sal_Int32 nX1, nY1;
1790 
1791                                                 Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize,
1792                                                     mrViewBox, bScale, bTranslate);
1793 
1794                                                 // write a quadratic curveto entry (Q)
1795                                                 if(bRelative)
1796                                                 {
1797                                                     if(aLastCommand != sal_Unicode('q'))
1798                                                         aNewString += OUString(sal_Unicode('q'));
1799 
1800                                                     Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1801                                                     Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1802                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1803                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1804 
1805                                                     aLastCommand = sal_Unicode('q');
1806                                                 }
1807                                                 else
1808                                                 {
1809                                                     if(aLastCommand != sal_Unicode('Q'))
1810                                                         aNewString += OUString(sal_Unicode('Q'));
1811 
1812                                                     Imp_PutNumberCharWithSpace(aNewString, nX1);
1813                                                     Imp_PutNumberCharWithSpace(aNewString, nY1);
1814                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1815                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1816 
1817                                                     aLastCommand = sal_Unicode('Q');
1818                                                 }
1819                                             }
1820                                         }
1821                                         else
1822                                         {
1823 #endif // TEST_QUADRATIC_CURVES
1824                                             awt::Point aNewPoint(nPX_L, nPY_L);
1825                                             bool bPrevPointIsSmooth(false);
1826 
1827                                             if(drawing::PolygonFlags_SMOOTH == aPrevFlag3)
1828                                             {
1829                                                 // get previous4 to see if it's a control point
1830                                                 awt::Point* pPrevPos4;
1831                                                 drawing::PolygonFlags aPrevFlag4;
1832 
1833                                                 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1834                                                     pFlags->getArray(), a, nCnt, 4);
1835 
1836                                                 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1837                                                 {
1838                                                     // okay, prevPos3 is smooth (c1) and prevPos4
1839                                                     // is existing control point. Test if it's even symmetric
1840                                                     // and thus the 'T' statement may be used.
1841                                                     ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y);
1842                                                     ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y);
1843                                                     bool bSameLength(false);
1844                                                     bool bSameDirection(false);
1845 
1846                                                     // get vector values
1847                                                     Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
1848 
1849                                                     if(bSameLength && bSameDirection)
1850                                                         bPrevPointIsSmooth = true;
1851                                                 }
1852                                             }
1853 
1854                                             if(bPrevPointIsSmooth)
1855                                             {
1856                                                 // write a shorthand/smooth quadratic curveto entry (T)
1857                                                 if(bRelative)
1858                                                 {
1859                                                     if(aLastCommand != sal_Unicode('t'))
1860                                                         aNewString += String(sal_Unicode('t'));
1861 
1862                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1863                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1864 
1865                                                     aLastCommand = sal_Unicode('t');
1866                                                 }
1867                                                 else
1868                                                 {
1869                                                     if(aLastCommand != sal_Unicode('T'))
1870                                                         aNewString += String(sal_Unicode('T'));
1871 
1872                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1873                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1874 
1875                                                     aLastCommand = sal_Unicode('T');
1876                                                 }
1877                                             }
1878                                             else
1879                                             {
1880                                                 // prepare coordinates
1881                                                 sal_Int32 nX1, nY1;
1882 
1883                                                 Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize,
1884                                                     mrViewBox, bScale, bTranslate);
1885 
1886                                                 // write a quadratic curveto entry (Q)
1887                                                 if(bRelative)
1888                                                 {
1889                                                     if(aLastCommand != sal_Unicode('q'))
1890                                                         aNewString += String(sal_Unicode('q'));
1891 
1892                                                     Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1893                                                     Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1894                                                     Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1895                                                     Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1896 
1897                                                     aLastCommand = sal_Unicode('q');
1898                                                 }
1899                                                 else
1900                                                 {
1901                                                     if(aLastCommand != sal_Unicode('Q'))
1902                                                         aNewString += String(sal_Unicode('Q'));
1903 
1904                                                     Imp_PutNumberCharWithSpace(aNewString, nX1);
1905                                                     Imp_PutNumberCharWithSpace(aNewString, nY1);
1906                                                     Imp_PutNumberCharWithSpace(aNewString, nX);
1907                                                     Imp_PutNumberCharWithSpace(aNewString, nY);
1908 
1909                                                     aLastCommand = sal_Unicode('Q');
1910                                                 }
1911                                             }
1912 #ifdef TEST_QUADRATIC_CURVES
1913                                         }
1914 #endif // TEST_QUADRATIC_CURVES
1915                                     }
1916                                     else
1917                                     {
1918                                         bool bPrevPointIsSymmetric(false);
1919 
1920                                         if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1921                                         {
1922                                             // get previous4 to see if it's a control point
1923                                             awt::Point* pPrevPos4;
1924                                             drawing::PolygonFlags aPrevFlag4;
1925 
1926                                             Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1927                                                 pFlags->getArray(), a, nCnt, 4);
1928 
1929                                             if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1930                                             {
1931                                                 // okay, prevPos3 is symmetric (c2) and prevPos4
1932                                                 // is existing control point, the 's' statement can be used
1933                                                 bPrevPointIsSymmetric = true;
1934                                             }
1935                                         }
1936 
1937                                         // prepare coordinates
1938                                         sal_Int32 nX2, nY2;
1939 
1940                                         Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize,
1941                                             mrViewBox, bScale, bTranslate);
1942 
1943                                         if(bPrevPointIsSymmetric)
1944                                         {
1945                                             // write a shorthand/smooth curveto entry (S)
1946                                             if(bRelative)
1947                                             {
1948                                                 if(aLastCommand != sal_Unicode('s'))
1949                                                     aNewString += String(sal_Unicode('s'));
1950 
1951                                                 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1952                                                 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1953                                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1954                                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1955 
1956                                                 aLastCommand = sal_Unicode('s');
1957                                             }
1958                                             else
1959                                             {
1960                                                 if(aLastCommand != sal_Unicode('S'))
1961                                                     aNewString += String(sal_Unicode('S'));
1962 
1963                                                 Imp_PutNumberCharWithSpace(aNewString, nX2);
1964                                                 Imp_PutNumberCharWithSpace(aNewString, nY2);
1965                                                 Imp_PutNumberCharWithSpace(aNewString, nX);
1966                                                 Imp_PutNumberCharWithSpace(aNewString, nY);
1967 
1968                                                 aLastCommand = sal_Unicode('S');
1969                                             }
1970                                         }
1971                                         else
1972                                         {
1973                                             // prepare coordinates
1974                                             sal_Int32 nX1, nY1;
1975 
1976                                             Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize,
1977                                                 mrViewBox, bScale, bTranslate);
1978 
1979                                             // write a curveto entry (C)
1980                                             if(bRelative)
1981                                             {
1982                                                 if(aLastCommand != sal_Unicode('c'))
1983                                                     aNewString += String(sal_Unicode('c'));
1984 
1985                                                 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1986                                                 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1987                                                 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1988                                                 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1989                                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1990                                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1991 
1992                                                 aLastCommand = sal_Unicode('c');
1993                                             }
1994                                             else
1995                                             {
1996                                                 if(aLastCommand != sal_Unicode('C'))
1997                                                     aNewString += String(sal_Unicode('C'));
1998 
1999                                                 Imp_PutNumberCharWithSpace(aNewString, nX1);
2000                                                 Imp_PutNumberCharWithSpace(aNewString, nY1);
2001                                                 Imp_PutNumberCharWithSpace(aNewString, nX2);
2002                                                 Imp_PutNumberCharWithSpace(aNewString, nY2);
2003                                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2004                                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2005 
2006                                                 aLastCommand = sal_Unicode('C');
2007                                             }
2008                                         }
2009                                     }
2010 
2011                                     // remember that current point IS written
2012                                     bDidWriteAsCurve = true;
2013 
2014                                     // remember new last position
2015                                     mnLastX = nX;
2016                                     mnLastY = nY;
2017                                 }
2018                             }
2019                         }
2020                     }
2021                 }
2022 
2023                 if(!bDidWriteAsCurve)
2024                 {
2025                     // current point not yet written, prepare coordinates
2026                     sal_Int32 nX, nY;
2027 
2028                     Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
2029                         mrViewBox, bScale, bTranslate);
2030 
2031                     if(bDidWriteStart)
2032                     {
2033                         // write as normal point
2034                         if(mnLastX == nX)
2035                         {
2036                             if(bRelative)
2037                             {
2038                                 if(aLastCommand != sal_Unicode('v'))
2039                                     aNewString += String(sal_Unicode('v'));
2040 
2041                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2042 
2043                                 aLastCommand = sal_Unicode('v');
2044                             }
2045                             else
2046                             {
2047                                 if(aLastCommand != sal_Unicode('V'))
2048                                     aNewString += String(sal_Unicode('V'));
2049 
2050                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2051 
2052                                 aLastCommand = sal_Unicode('V');
2053                             }
2054                         }
2055                         else if(mnLastY == nY)
2056                         {
2057                             if(bRelative)
2058                             {
2059                                 if(aLastCommand != sal_Unicode('h'))
2060                                     aNewString += String(sal_Unicode('h'));
2061 
2062                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2063 
2064                                 aLastCommand = sal_Unicode('h');
2065                             }
2066                             else
2067                             {
2068                                 if(aLastCommand != sal_Unicode('H'))
2069                                     aNewString += String(sal_Unicode('H'));
2070 
2071                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2072 
2073                                 aLastCommand = sal_Unicode('H');
2074                             }
2075                         }
2076                         else
2077                         {
2078                             if(bRelative)
2079                             {
2080                                 if(aLastCommand != sal_Unicode('l'))
2081                                     aNewString += String(sal_Unicode('l'));
2082 
2083                                 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2084                                 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2085 
2086                                 aLastCommand = sal_Unicode('l');
2087                             }
2088                             else
2089                             {
2090                                 if(aLastCommand != sal_Unicode('L'))
2091                                     aNewString += String(sal_Unicode('L'));
2092 
2093                                 Imp_PutNumberCharWithSpace(aNewString, nX);
2094                                 Imp_PutNumberCharWithSpace(aNewString, nY);
2095 
2096                                 aLastCommand = sal_Unicode('L');
2097                             }
2098                         }
2099                     }
2100                     else
2101                     {
2102                         // write as start point
2103                         if(bRelative)
2104                         {
2105                             aNewString += String(sal_Unicode('m'));
2106 
2107                             Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2108                             Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2109 
2110                             aLastCommand = sal_Unicode('l');
2111                         }
2112                         else
2113                         {
2114                             aNewString += String(sal_Unicode('M'));
2115 
2116                             Imp_PutNumberCharWithSpace(aNewString, nX);
2117                             Imp_PutNumberCharWithSpace(aNewString, nY);
2118 
2119                             aLastCommand = sal_Unicode('L');
2120                         }
2121 
2122                         // remember start written
2123                         bDidWriteStart = true;
2124                     }
2125 
2126                     // remember new last position
2127                     mnLastX = nX;
2128                     mnLastY = nY;
2129                 }
2130             }
2131 
2132             // next point
2133             pPointArray++;
2134             pFlagArray++;
2135         }
2136 
2137         // close path if closed poly
2138         if(bClosed)
2139         {
2140             if(bRelative)
2141                 aNewString += String(sal_Unicode('z'));
2142             else
2143                 aNewString += String(sal_Unicode('Z'));
2144         }
2145 
2146         // append new string
2147         msString += aNewString;
2148     }
2149 }
2150 
2151 // #100617# Linear double reader
2152 double Imp_ImportDoubleAndSpaces(
2153     double fRetval, const OUString& rStr, sal_Int32& rPos,
2154     const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2155 {
2156     fRetval = Imp_GetDoubleChar(rStr, rPos, nLen, rConv, fRetval);
2157     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2158     return fRetval;
2159 }
2160 
2161 // #100617# Allow to read doubles, too. This will need to be changed to
2162 // the usage of Imp_ImportDoubleAndSpaces(...). For now, this is sufficient
2163 // since the interface cannot transport doubles.
2164 sal_Int32 Imp_ImportNumberAndSpaces(
2165     sal_Int32 nRetval, const OUString& rStr, sal_Int32& rPos,
2166     const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2167 {
2168     nRetval = FRound(Imp_ImportDoubleAndSpaces(double(nRetval), rStr, rPos, nLen, rConv));
2169     Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2170     return nRetval;
2171 }
2172 
2173 void Imp_PrepareCoorImport(sal_Int32& nX, sal_Int32& nY,
2174     const awt::Point& rObjectPos, const awt::Size& rObjectSize,
2175     const SdXMLImExViewBox& rViewBox, const bool bScale, const bool bTranslate)
2176 {
2177     if(bTranslate)
2178     {
2179         nX -= rViewBox.GetX();
2180         nY -= rViewBox.GetY();
2181     }
2182 
2183     if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight())
2184     {
2185         nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
2186         nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
2187     }
2188 
2189     nX += rObjectPos.X;
2190     nY += rObjectPos.Y;
2191 }
2192 
2193 void Imp_AddExportPoints(sal_Int32 nX, sal_Int32 nY,
2194     awt::Point* pPoints, drawing::PolygonFlags* pFlags,
2195     const sal_Int32 nInnerIndex,
2196     drawing::PolygonFlags eFlag)
2197 {
2198     if(pPoints)
2199         pPoints[nInnerIndex] = awt::Point( nX, nY );
2200 
2201     if(pFlags)
2202         pFlags[nInnerIndex] = eFlag;
2203 }
2204 
2205 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection)
2206 {
2207     const sal_Int32 nLen1(FRound(aVec1.getLength()));
2208     const sal_Int32 nLen2(FRound(aVec2.getLength()));
2209     aVec1.normalize();
2210     aVec2.normalize();
2211     aVec1 += aVec2;
2212     const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0)));
2213 
2214     bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL);
2215     bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL);
2216 }
2217 
2218 void Imp_CorrectPolygonFlag(const sal_uInt32 nInnerIndex, const awt::Point* const pInnerSequence,
2219     drawing::PolygonFlags* const pInnerFlags, const sal_Int32 nX1, const sal_Int32 nY1)
2220 {
2221     if(nInnerIndex)
2222     {
2223         const awt::Point aPPrev1 = pInnerSequence[nInnerIndex - 1];
2224 
2225         if(nInnerIndex > 1)
2226         {
2227             const awt::Point aPPrev2 = pInnerSequence[nInnerIndex - 2];
2228             const drawing::PolygonFlags aFPrev2 = pInnerFlags[nInnerIndex - 2];
2229             ::basegfx::B2DVector aVec1(aPPrev2.X - aPPrev1.X, aPPrev2.Y - aPPrev1.Y);
2230             ::basegfx::B2DVector aVec2(nX1 - aPPrev1.X, nY1 - aPPrev1.Y);
2231             bool bSameLength(false);
2232             bool bSameDirection(false);
2233 
2234             // get vector values
2235             Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
2236 
2237             if(drawing::PolygonFlags_CONTROL == aFPrev2)
2238             {
2239                 // point before is a control point
2240                 if(bSameDirection)
2241                 {
2242                     if(bSameLength)
2243                     {
2244                         // set to PolygonFlags_SYMMETRIC
2245                         pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2246                     }
2247                     else
2248                     {
2249                         // set to PolygonFlags_SMOOTH
2250                         pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2251                     }
2252                 }
2253                 else
2254                 {
2255                     // set to PolygonFlags_NORMAL
2256                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2257                 }
2258             }
2259             else
2260             {
2261                 // point before is a simple curve point
2262                 if(bSameDirection)
2263                 {
2264                     // set to PolygonFlags_SMOOTH
2265                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2266                 }
2267                 else
2268                 {
2269                     // set to PolygonFlags_NORMAL
2270                     pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2271                 }
2272             }
2273         }
2274         else
2275         {
2276             // no point before starpoint, set type to PolygonFlags_NORMAL
2277             pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2278         }
2279     }
2280 }
2281 
2282 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew,
2283     const SdXMLImExViewBox& rViewBox,
2284     const awt::Point& rObjectPos,
2285     const awt::Size& rObjectSize,
2286     const SvXMLUnitConverter& rConv)
2287 :   msString( rNew ),
2288     mrViewBox( rViewBox ),
2289     mbIsClosed( false ),
2290     mbIsCurve( false ),
2291     mnLastX( 0L ),
2292     mnLastY( 0L ),
2293     maPoly( 0L ),
2294     maFlag( 0L )
2295 {
2296     // convert string to polygon
2297     const OUString aStr(msString.getStr(), msString.getLength());
2298     const sal_Int32 nLen(aStr.getLength());
2299     sal_Int32 nPos(0);
2300     sal_Int32 nNumPolys(0L);
2301     bool bEllipticalArc(false);
2302 
2303     // object size and ViewBox size different?
2304     bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
2305         || rObjectSize.Height != mrViewBox.GetHeight());
2306     bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
2307 
2308     // first loop: count polys and get flags
2309     Imp_SkipSpaces(aStr, nPos, nLen);
2310 
2311     while(nPos < nLen)
2312     {
2313         switch(aStr[nPos++])
2314         {
2315             case 'Z' :
2316             case 'z' :
2317             {
2318                 break;
2319             }
2320             case 'M' :
2321             case 'm' :
2322             {
2323                 nNumPolys++;
2324                 break;
2325             }
2326             case 'S' :
2327             case 's' :
2328             case 'C' :
2329             case 'c' :
2330             case 'Q' :
2331             case 'q' :
2332             case 'T' :
2333             case 't' :
2334             {
2335                 mbIsCurve = true;
2336                 break;
2337             }
2338             case 'L' :
2339             case 'l' :
2340             case 'H' :
2341             case 'h' :
2342             case 'V' :
2343             case 'v' :
2344             {
2345                 // normal, interpreted values. All okay.
2346                 break;
2347             }
2348             case 'A' :
2349             case 'a' :
2350             {
2351                 // Not yet interpreted value.
2352                 bEllipticalArc = true;
2353                 break;
2354             }
2355         }
2356     }
2357 
2358     DBG_ASSERT(!bEllipticalArc, "XMLIMP: non-interpreted tags in svg:d element!");
2359 
2360     if(nNumPolys)
2361     {
2362         // alloc arrays
2363         maPoly.realloc(nNumPolys);
2364         if(IsCurve())
2365             maFlag.realloc(nNumPolys);
2366 
2367         // get outer sequences
2368         drawing::PointSequence* pOuterSequence = maPoly.getArray();
2369         drawing::FlagSequence* pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2370 
2371         // prepare new loop, count
2372         sal_uInt32 nPointCount(0L);
2373         nPos = 0;
2374         Imp_SkipSpaces(aStr, nPos, nLen);
2375 
2376         // #104076# reset closed flag for next to be started polygon
2377         mbIsClosed = false;
2378 
2379         while(nPos < nLen)
2380         {
2381             switch(aStr[nPos])
2382             {
2383                 case 'z' :
2384                 case 'Z' :
2385                 {
2386                     nPos++;
2387                     Imp_SkipSpaces(aStr, nPos, nLen);
2388 
2389                     // #104076# remember closed state of current polygon
2390                     mbIsClosed = true;
2391 
2392                     break;
2393                 }
2394                 case 'm' :
2395                 case 'M' :
2396                 {
2397                     // new poly starts, end-process current poly
2398                     if(nPointCount)
2399                     {
2400                         // #104076# If this partial polygon is closed, use one more point
2401                         // to represent that
2402                         if(mbIsClosed)
2403                         {
2404                             nPointCount++;
2405                         }
2406 
2407                         pOuterSequence->realloc(nPointCount);
2408                         pOuterSequence++;
2409 
2410                         if(pOuterFlags)
2411                         {
2412                             pOuterFlags->realloc(nPointCount);
2413                             pOuterFlags++;
2414                         }
2415 
2416                         // reset point count for next polygon
2417                         nPointCount = 0L;
2418                     }
2419 
2420                     // #104076# reset closed flag for next to be started polygon
2421                     mbIsClosed = false;
2422 
2423                     // NO break, continue in next case
2424                 }
2425                 case 'L' :
2426                 case 'l' :
2427                 {
2428                     nPos++;
2429                     Imp_SkipSpaces(aStr, nPos, nLen);
2430 
2431                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2432                     {
2433                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2434                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2435                         nPointCount++;
2436                     }
2437                     break;
2438                 }
2439                 case 'H' :
2440                 case 'h' :
2441                 case 'V' :
2442                 case 'v' :
2443                 {
2444                     nPos++;
2445                     Imp_SkipSpaces(aStr, nPos, nLen);
2446 
2447                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2448                     {
2449                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2450                         nPointCount++;
2451                     }
2452                     break;
2453                 }
2454                 case 'S' :
2455                 case 's' :
2456                 {
2457                     nPos++;
2458                     Imp_SkipSpaces(aStr, nPos, nLen);
2459 
2460                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2461                     {
2462                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2463                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2464                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2465                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2466                         nPointCount += 3;
2467                     }
2468                     break;
2469                 }
2470                 case 'C' :
2471                 case 'c' :
2472                 {
2473                     nPos++;
2474                     Imp_SkipSpaces(aStr, nPos, nLen);
2475 
2476                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2477                     {
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                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2483                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2484                         nPointCount += 3;
2485                     }
2486                     break;
2487                 }
2488 
2489                 // #100617# quadratic beziers, supported as cubic ones
2490                 case 'Q' :
2491                 case 'q' :
2492                 {
2493                     nPos++;
2494                     Imp_SkipSpaces(aStr, nPos, nLen);
2495 
2496                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2497                     {
2498                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2499                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2500                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2501                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2502 
2503                         // use three points since quadratic is imported as cubic
2504                         nPointCount += 3;
2505                     }
2506                     break;
2507                 }
2508 
2509                 // #100617# relative quadratic beziers, supported as cubic ones
2510                 case 'T' :
2511                 case 't' :
2512                 {
2513                     nPos++;
2514                     Imp_SkipSpaces(aStr, nPos, nLen);
2515 
2516                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2517                     {
2518                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2519                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2520 
2521                         // use three points since quadratic is imported as cubic
2522                         nPointCount += 3;
2523                     }
2524                     break;
2525                 }
2526 
2527                 // #100617# not yet supported: elliptical arc
2528                 case 'A' :
2529                 case 'a' :
2530                 {
2531                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2532                     nPos++;
2533                     Imp_SkipSpaces(aStr, nPos, nLen);
2534 
2535                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2536                     {
2537                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2538                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2539                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2540                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2541                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2542                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2543                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2544                     }
2545                     break;
2546                 }
2547 
2548                 default:
2549                 {
2550                     nPos++;
2551                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
2552                     break;
2553                 }
2554             }
2555         }
2556 
2557         // alloc last poly (when points used)
2558         if(nPointCount)
2559         {
2560             // #104076# If this partial polygon is closed, use one more point
2561             // to represent that
2562             if(mbIsClosed)
2563             {
2564                 nPointCount++;
2565             }
2566 
2567             pOuterSequence->realloc(nPointCount);
2568             pOuterSequence++;
2569 
2570             if(pOuterFlags)
2571             {
2572                 pOuterFlags->realloc(nPointCount);
2573                 pOuterFlags++;
2574             }
2575         }
2576 
2577         // set pointers back
2578         pOuterSequence = maPoly.getArray();
2579         pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2580         awt::Point* pNotSoInnerSequence = 0L;
2581         drawing::PolygonFlags* pNotSoInnerFlags = 0L;
2582         sal_uInt32 nInnerIndex(0L);
2583 
2584         // prepare new loop, read points
2585         nPos = 0;
2586         Imp_SkipSpaces(aStr, nPos, nLen);
2587 
2588         // #104076# reset closed flag for next to be started polygon
2589         mbIsClosed = false;
2590 
2591         while(nPos < nLen)
2592         {
2593             bool bRelative(false);
2594 
2595             switch(aStr[nPos])
2596             {
2597                 case 'z' :
2598                 case 'Z' :
2599                 {
2600                     nPos++;
2601                     Imp_SkipSpaces(aStr, nPos, nLen);
2602 
2603                     // #104076# remember closed state of current polygon
2604                     mbIsClosed = true;
2605 
2606                     // closed: add first point again
2607                     // sal_Int32 nX(pInnerSequence[0].X);
2608                     // sal_Int32 nY(pInnerSequence[0].Y);
2609                     // Imp_AddExportPoints(nX, nY, pInnerSequence, pInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2610 
2611                     break;
2612                 }
2613 
2614                 case 'm' :
2615                 {
2616                     bRelative = true;
2617                 }
2618                 case 'M' :
2619                 {
2620                     // #104076# end-process current poly
2621                     if(mbIsClosed)
2622                     {
2623                         if(pNotSoInnerSequence)
2624                         {
2625                             // closed: add first point again
2626                             sal_Int32 nX(pNotSoInnerSequence[0].X);
2627                             sal_Int32 nY(pNotSoInnerSequence[0].Y);
2628                             Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2629                         }
2630 
2631                         // reset closed flag for next to be started polygon
2632                         mbIsClosed = false;
2633                     }
2634 
2635                     // next poly
2636                     pNotSoInnerSequence = pOuterSequence->getArray();
2637                     pOuterSequence++;
2638 
2639                     if(pOuterFlags)
2640                     {
2641                         pNotSoInnerFlags = pOuterFlags->getArray();
2642                         pOuterFlags++;
2643                     }
2644 
2645                     nInnerIndex = 0L;
2646 
2647                     nPos++;
2648                     Imp_SkipSpaces(aStr, nPos, nLen);
2649 
2650                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2651                     {
2652                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2653                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2654 
2655                         if(bRelative)
2656                         {
2657                             nX += mnLastX;
2658                             nY += mnLastY;
2659                         }
2660 
2661                         // set last position
2662                         mnLastX = nX;
2663                         mnLastY = nY;
2664 
2665                         // calc transform and add point and flag
2666                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2667                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2668                     }
2669                     break;
2670                 }
2671 
2672                 case 'l' :
2673                 {
2674                     bRelative = true;
2675                 }
2676                 case 'L' :
2677                 {
2678                     nPos++;
2679                     Imp_SkipSpaces(aStr, nPos, nLen);
2680 
2681                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2682                     {
2683                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2684                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2685 
2686                         if(bRelative)
2687                         {
2688                             nX += mnLastX;
2689                             nY += mnLastY;
2690                         }
2691 
2692                         // set last position
2693                         mnLastX = nX;
2694                         mnLastY = nY;
2695 
2696                         // calc transform and add point and flag
2697                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2698                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2699                     }
2700                     break;
2701                 }
2702 
2703                 case 'h' :
2704                 {
2705                     bRelative = true;
2706                 }
2707                 case 'H' :
2708                 {
2709                     nPos++;
2710                     Imp_SkipSpaces(aStr, nPos, nLen);
2711 
2712                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2713                     {
2714                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2715                         sal_Int32 nY(mnLastY);
2716 
2717                         if(bRelative)
2718                             nX += mnLastX;
2719 
2720                         // set last position
2721                         mnLastX = nX;
2722 
2723                         // calc transform and add point and flag
2724                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2725                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2726                     }
2727                     break;
2728                 }
2729 
2730                 case 'v' :
2731                 {
2732                     bRelative = true;
2733                 }
2734                 case 'V' :
2735                 {
2736                     nPos++;
2737                     Imp_SkipSpaces(aStr, nPos, nLen);
2738 
2739                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2740                     {
2741                         sal_Int32 nX(mnLastX);
2742                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2743 
2744                         if(bRelative)
2745                             nY += mnLastY;
2746 
2747                         // set last position
2748                         mnLastY = nY;
2749 
2750                         // calc transform and add point and flag
2751                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2752                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2753                     }
2754                     break;
2755                 }
2756 
2757                 case 's' :
2758                 {
2759                     bRelative = true;
2760                 }
2761                 case 'S' :
2762                 {
2763                     nPos++;
2764                     Imp_SkipSpaces(aStr, nPos, nLen);
2765 
2766                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2767                     {
2768                         sal_Int32 nX1;
2769                         sal_Int32 nY1;
2770                         sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2771                         sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2772                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2773                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2774 
2775                         if(bRelative)
2776                         {
2777                             nX2 += mnLastX;
2778                             nY2 += mnLastY;
2779                             nX += mnLastX;
2780                             nY += mnLastY;
2781                         }
2782 
2783                         // set last position
2784                         mnLastX = nX;
2785                         mnLastY = nY;
2786 
2787                         // calc transform for new points
2788                         Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2789                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2790 
2791                         // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2792                         // and the Point X1,Y1 can be constructed by mirroring the point before it.
2793                         nX1 = nX2;
2794                         nY1 = nY2;
2795                         if(nInnerIndex)
2796                         {
2797                             awt::Point aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2798 
2799                             if(nInnerIndex > 1)
2800                             {
2801                                 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2802                                 nX1 = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2803                                 nY1 = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2804                             }
2805 
2806                             // set curve point to symmetric
2807                             pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2808                         }
2809 
2810                         // add calculated control point
2811                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2812 
2813                         // add new points and set flags
2814                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2815                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2816                     }
2817                     break;
2818                 }
2819 
2820                 case 'c' :
2821                 {
2822                     bRelative = true;
2823                 }
2824                 case 'C' :
2825                 {
2826                     nPos++;
2827                     Imp_SkipSpaces(aStr, nPos, nLen);
2828 
2829                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2830                     {
2831                         sal_Int32 nX1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2832                         sal_Int32 nY1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2833                         sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2834                         sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2835                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2836                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2837 
2838                         if(bRelative)
2839                         {
2840                             nX1 += mnLastX;
2841                             nY1 += mnLastY;
2842                             nX2 += mnLastX;
2843                             nY2 += mnLastY;
2844                             nX += mnLastX;
2845                             nY += mnLastY;
2846                         }
2847 
2848                         // set last position
2849                         mnLastX = nX;
2850                         mnLastY = nY;
2851 
2852                         // calc transform for new points
2853                         Imp_PrepareCoorImport(nX1, nY1, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2854                         Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2855                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2856 
2857                         // correct polygon flag for previous point
2858                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2859 
2860                         // add new points and set flags
2861                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2862                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2863                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2864                     }
2865                     break;
2866                 }
2867 
2868                 // #100617# quadratic beziers are imported as cubic
2869                 case 'q' :
2870                 {
2871                     bRelative = true;
2872                 }
2873                 case 'Q' :
2874                 {
2875                     nPos++;
2876                     Imp_SkipSpaces(aStr, nPos, nLen);
2877 
2878                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2879                     {
2880                         sal_Int32 nXX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2881                         sal_Int32 nYY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2882                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2883                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2884 
2885                         if(bRelative)
2886                         {
2887                             nXX += mnLastX;
2888                             nYY += mnLastY;
2889                             nX += mnLastX;
2890                             nY += mnLastY;
2891                         }
2892 
2893                         // set last position
2894                         mnLastX = nX;
2895                         mnLastY = nY;
2896 
2897                         // calc transform for new points
2898                         Imp_PrepareCoorImport(nXX, nYY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2899                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2900 
2901                         // calculate X1,X2
2902                         awt::Point aPPrev1 = (nInnerIndex) ? pNotSoInnerSequence[nInnerIndex-1] : pNotSoInnerSequence[0];
2903                         sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2904                         sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2905                         sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2906                         sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2907 
2908                         // correct polygon flag for previous point
2909                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2910 
2911                         // add new points and set flags
2912                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2913                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2914                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2915                     }
2916                     break;
2917                 }
2918 
2919                 // #100617# relative quadratic beziers are imported as cubic
2920                 case 't' :
2921                 {
2922                     bRelative = true;
2923                 }
2924                 case 'T' :
2925                 {
2926                     nPos++;
2927                     Imp_SkipSpaces(aStr, nPos, nLen);
2928 
2929                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2930                     {
2931                         sal_Int32 nXX;
2932                         sal_Int32 nYY;
2933                         sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2934                         sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv));
2935 
2936                         if(bRelative)
2937                         {
2938                             nX += mnLastX;
2939                             nY += mnLastY;
2940                         }
2941 
2942                         // set last position
2943                         mnLastX = nX;
2944                         mnLastY = nY;
2945 
2946                         // calc transform for new points
2947                         Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2948 
2949                         // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2950                         // and the Point X1,Y1 can be constructed by mirroring the point before it.
2951                         nXX = nX;
2952                         nYY = nY;
2953                         awt::Point aPPrev1 = pNotSoInnerSequence[0];
2954 
2955                         if(nInnerIndex)
2956                         {
2957                             aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2958 
2959                             if(nInnerIndex > 1)
2960                             {
2961                                 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2962                                 nXX = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2963                                 nYY = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2964                             }
2965 
2966                             // set curve point to smooth here, since length
2967                             // is changed and thus only c1 can be used.
2968                             pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2969                         }
2970 
2971                         // calculate X1,X2
2972                         sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2973                         sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2974                         sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2975                         sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2976 
2977                         // correct polygon flag for previous point
2978                         Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2979 
2980                         // add new points and set flags
2981                         Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2982                         Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2983                         Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2984                     }
2985                     break;
2986                 }
2987 
2988                 // #100617# not yet supported: elliptical arc
2989                 case 'A' :
2990                 case 'a' :
2991                 {
2992                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2993                     nPos++;
2994                     Imp_SkipSpaces(aStr, nPos, nLen);
2995 
2996                     while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2997                     {
2998                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2999                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3000                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3001                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3002                         Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3003                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3004                         Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3005                     }
3006                     break;
3007                 }
3008 
3009                 default:
3010                 {
3011                     nPos++;
3012                     DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
3013                     break;
3014                 }
3015             }
3016         }
3017 
3018         // #104076# end-process closed state of last poly
3019         if(mbIsClosed)
3020         {
3021             if(pNotSoInnerSequence)
3022             {
3023                 // closed: add first point again
3024                 sal_Int32 nX(pNotSoInnerSequence[0].X);
3025                 sal_Int32 nY(pNotSoInnerSequence[0].Y);
3026                 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
3027             }
3028         }
3029 
3030         // #87202# If it's a curve and it's closed the last point maybe too much
3031         // and just exported since SVG does not allow special handling of same
3032         // start and end point, remove this last point.
3033         // Evtl. correct the last curve flags, too.
3034         if(IsCurve() && IsClosed())
3035         {
3036             // make one more loop over the PolyPolygon
3037             pOuterSequence = maPoly.getArray();
3038             pOuterFlags = maFlag.getArray();
3039             sal_Int32 nOuterCnt(maPoly.getLength());
3040 
3041             for(sal_Int32 a(0); a < nOuterCnt; a++)
3042             {
3043                 // get Polygon pointers
3044                 awt::Point* pInnerSequence = pOuterSequence->getArray();
3045                 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
3046                 sal_Int32 nInnerCnt(pOuterSequence->getLength());
3047 
3048                 while( nInnerCnt >= 2
3049                     && ((pInnerSequence + (nInnerCnt - 2))->X == (pInnerSequence + (nInnerCnt - 1))->X)
3050                     && ((pInnerSequence + (nInnerCnt - 2))->Y == (pInnerSequence + (nInnerCnt - 1))->Y)
3051                     && drawing::PolygonFlags_CONTROL != *(pInnerFlags + (nInnerCnt - 2)))
3052                 {
3053                     // remove last point from array
3054                     pOuterSequence->realloc(nInnerCnt - 1);
3055                     pOuterFlags->realloc(nInnerCnt - 1);
3056 
3057                     // get new pointers
3058                     pInnerSequence = pOuterSequence->getArray();
3059                     pInnerFlags = pOuterFlags->getArray();
3060                     nInnerCnt = pOuterSequence->getLength();
3061                 }
3062 
3063                 // now evtl. correct the last curve flags
3064                 if(nInnerCnt >= 4)
3065                 {
3066                     if( pInnerSequence->X == (pInnerSequence + (nInnerCnt - 1))->X
3067                         && pInnerSequence->Y == (pInnerSequence + (nInnerCnt - 1))->Y
3068                         && drawing::PolygonFlags_CONTROL == *(pInnerFlags + 1)
3069                         && drawing::PolygonFlags_CONTROL == *(pInnerFlags + (nInnerCnt - 2)))
3070                     {
3071                         awt::Point aPrev = *(pInnerSequence + (nInnerCnt - 2));
3072                         awt::Point aCurr = *pInnerSequence;
3073                         awt::Point aNext = *(pInnerSequence + 1);
3074                         ::basegfx::B2DVector aVec1(aPrev.X - aCurr.X, aPrev.Y - aCurr.Y);
3075                         ::basegfx::B2DVector aVec2(aNext.X - aCurr.X, aNext.Y - aCurr.Y);
3076                         bool bSameLength(false);
3077                         bool bSameDirection(false);
3078 
3079                         // get vector values
3080                         Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
3081 
3082                         // set correct flag value
3083                         if(bSameDirection)
3084                         {
3085                             if(bSameLength)
3086                             {
3087                                 // set to PolygonFlags_SYMMETRIC
3088                                 *pInnerFlags = drawing::PolygonFlags_SYMMETRIC;
3089                                 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SYMMETRIC;
3090                             }
3091                             else
3092                             {
3093                                 // set to PolygonFlags_SMOOTH
3094                                 *pInnerFlags = drawing::PolygonFlags_SMOOTH;
3095                                 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SMOOTH;
3096                             }
3097                         }
3098                         else
3099                         {
3100                             // set to PolygonFlags_NORMAL
3101                             *pInnerFlags = drawing::PolygonFlags_NORMAL;
3102                             *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_NORMAL;
3103                         }
3104                     }
3105                 }
3106 
3107                 // switch to next Polygon
3108                 pOuterSequence++;
3109                 pOuterFlags++;
3110             }
3111         }
3112     }
3113 }
3114 
3115 // eof
3116