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