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