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