merge the formfield patch from ooo-build
[ooovba.git] / xmloff / source / draw / xexptran.cxx
blob67fb651b5beafa9a100aae467b84820103701924
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xexptran.cxx,v $
10 * $Revision: 1.29 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmloff.hxx"
33 #include "xexptran.hxx"
34 #include <tools/debug.hxx>
35 #include <rtl/ustrbuf.hxx>
36 #include <xmloff/xmluconv.hxx>
37 #include <vcl/salbtype.hxx>
38 #include <basegfx/vector/b2dvector.hxx>
39 #include <basegfx/matrix/b2dhommatrix.hxx>
40 #include <basegfx/tuple/b3dtuple.hxx>
41 #include <basegfx/matrix/b3dhommatrix.hxx>
42 #include <tools/string.hxx>
44 using ::rtl::OUString;
45 using ::rtl::OUStringBuffer;
47 using namespace ::com::sun::star;
49 //////////////////////////////////////////////////////////////////////////////
50 // Defines
52 #define BORDER_INTEGERS_ARE_EQUAL (4)
54 //////////////////////////////////////////////////////////////////////////////
55 // Predeclarations
57 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen);
58 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection);
60 //////////////////////////////////////////////////////////////////////////////
61 //////////////////////////////////////////////////////////////////////////////
62 // parsing help functions for simple chars
63 void Imp_SkipSpaces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
65 while(rPos < nLen
66 && sal_Unicode(' ') == rStr[rPos])
67 rPos++;
70 void Imp_SkipSpacesAndOpeningBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
72 while(rPos < nLen
73 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode('(') == rStr[rPos]))
74 rPos++;
77 void Imp_SkipSpacesAndCommas(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
79 while(rPos < nLen
80 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(',') == rStr[rPos]))
81 rPos++;
84 void Imp_SkipSpacesAndClosingBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
86 while(rPos < nLen
87 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(')') == rStr[rPos]))
88 rPos++;
91 //////////////////////////////////////////////////////////////////////////////
92 //////////////////////////////////////////////////////////////////////////////
93 // parsing help functions for integer numbers
95 bool Imp_IsOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
97 sal_Unicode aChar(rStr[nPos]);
99 if((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
100 || (bSignAllowed && sal_Unicode('+') == aChar)
101 || (bSignAllowed && sal_Unicode('-') == aChar)
103 return true;
104 return false;
107 bool Imp_IsOnUnitChar(const OUString& rStr, const sal_Int32 nPos)
109 sal_Unicode aChar(rStr[nPos]);
111 if((sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
112 || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
113 || sal_Unicode('%') == aChar
115 return true;
116 return false;
119 void Imp_SkipNumber(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
121 bool bSignAllowed(true);
123 while(rPos < nLen && Imp_IsOnNumberChar(rStr, rPos, bSignAllowed))
125 bSignAllowed = false;
126 rPos++;
130 void Imp_SkipNumberAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
131 const sal_Int32 nLen)
133 Imp_SkipNumber(rStr, rPos, nLen);
134 Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
137 // #100617# Allow to skip doubles, too.
138 void Imp_SkipDoubleAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
139 const sal_Int32 nLen)
141 Imp_SkipDouble(rStr, rPos, nLen);
142 Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
145 void Imp_PutNumberChar(OUString& rStr, sal_Int32 nValue)
147 OUStringBuffer sStringBuffer;
148 SvXMLUnitConverter::convertNumber(sStringBuffer, nValue);
149 rStr += OUString(sStringBuffer.makeStringAndClear());
152 void Imp_PutNumberCharWithSpace(OUString& rStr, sal_Int32 nValue)
154 const sal_Int32 aLen(rStr.getLength());
155 if(aLen)
156 if(Imp_IsOnNumberChar(rStr, aLen - 1, false) && nValue >= 0)
157 rStr += String(sal_Unicode(' '));
158 Imp_PutNumberChar(rStr, nValue);
161 //////////////////////////////////////////////////////////////////////////////
162 //////////////////////////////////////////////////////////////////////////////
163 // parsing help functions for double numbers
165 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32)
167 sal_Unicode aChar(rStr[rPos]);
169 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
170 aChar = rStr[++rPos];
172 while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
173 || sal_Unicode('.') == aChar)
175 aChar = rStr[++rPos];
178 if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
180 aChar = rStr[++rPos];
182 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
183 aChar = rStr[++rPos];
185 while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
187 aChar = rStr[++rPos];
192 double Imp_GetDoubleChar(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen,
193 const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false)
195 sal_Unicode aChar(rStr[rPos]);
196 OUStringBuffer sNumberString;
198 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
200 sNumberString.append(rStr[rPos]);
201 aChar = rStr[++rPos];
204 while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
205 || sal_Unicode('.') == aChar)
207 sNumberString.append(rStr[rPos]);
208 aChar = rStr[++rPos];
211 if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
213 sNumberString.append(rStr[rPos]);
214 aChar = rStr[++rPos];
216 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
218 sNumberString.append(rStr[rPos]);
219 aChar = rStr[++rPos];
222 while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
224 sNumberString.append(rStr[rPos]);
225 aChar = rStr[++rPos];
229 if(bLookForUnits)
231 Imp_SkipSpaces(rStr, rPos, nLen);
232 while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos))
233 sNumberString.append(rStr[rPos++]);
236 if(sNumberString.getLength())
238 if(bLookForUnits)
239 rConv.convertDouble(fRetval, sNumberString.makeStringAndClear(), true);
240 else
241 rConv.convertDouble(fRetval, sNumberString.makeStringAndClear());
244 return fRetval;
247 void Imp_PutDoubleChar(OUString& rStr, const SvXMLUnitConverter& rConv, double fValue,
248 bool bConvertUnits = false)
250 OUStringBuffer sStringBuffer;
252 if(bConvertUnits)
253 rConv.convertDouble(sStringBuffer, fValue, true);
254 else
255 rConv.convertDouble(sStringBuffer, fValue);
257 rStr += OUString(sStringBuffer.makeStringAndClear());
260 //////////////////////////////////////////////////////////////////////////////
261 //////////////////////////////////////////////////////////////////////////////
262 // base class of all 2D transform objects
264 struct ImpSdXMLExpTransObj2DBase
266 sal_uInt16 mnType;
267 ImpSdXMLExpTransObj2DBase(sal_uInt16 nType)
268 : mnType(nType) {}
271 //////////////////////////////////////////////////////////////////////////////
272 // possible object types for 2D
274 #define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000
275 #define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001
276 #define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002
277 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003
278 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004
279 #define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005
281 //////////////////////////////////////////////////////////////////////////////
282 // classes of objects, different sizes
284 struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase
286 double mfRotate;
287 ImpSdXMLExpTransObj2DRotate(double fVal)
288 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {}
290 struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase
292 ::basegfx::B2DTuple maScale;
293 ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew)
294 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {}
296 struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase
298 ::basegfx::B2DTuple maTranslate;
299 ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew)
300 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {}
302 struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase
304 double mfSkewX;
305 ImpSdXMLExpTransObj2DSkewX(double fVal)
306 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {}
308 struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase
310 double mfSkewY;
311 ImpSdXMLExpTransObj2DSkewY(double fVal)
312 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {}
314 struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase
316 ::basegfx::B2DHomMatrix maMatrix;
317 ImpSdXMLExpTransObj2DMatrix(const ::basegfx::B2DHomMatrix& rNew)
318 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(rNew) {}
321 //////////////////////////////////////////////////////////////////////////////
322 //////////////////////////////////////////////////////////////////////////////
323 // delete all entries in list
325 void SdXMLImExTransform2D::EmptyList()
327 const sal_uInt32 nCount = maList.size();
328 for(sal_uInt32 a(0L); a < nCount; a++)
330 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
332 switch(pObj->mnType)
334 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
336 delete (ImpSdXMLExpTransObj2DRotate*)pObj;
337 break;
339 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
341 delete (ImpSdXMLExpTransObj2DScale*)pObj;
342 break;
344 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
346 delete (ImpSdXMLExpTransObj2DTranslate*)pObj;
347 break;
349 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
351 delete (ImpSdXMLExpTransObj2DSkewX*)pObj;
352 break;
354 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
356 delete (ImpSdXMLExpTransObj2DSkewY*)pObj;
357 break;
359 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
361 delete (ImpSdXMLExpTransObj2DMatrix*)pObj;
362 break;
364 default :
366 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
367 break;
372 maList.clear();
375 //////////////////////////////////////////////////////////////////////////////
376 // add members
378 void SdXMLImExTransform2D::AddRotate(double fNew)
380 if(fNew != 0.0)
381 maList.push_back(new ImpSdXMLExpTransObj2DRotate(fNew));
384 void SdXMLImExTransform2D::AddScale(const ::basegfx::B2DTuple& rNew)
386 if(1.0 != rNew.getX() || 1.0 != rNew.getY())
387 maList.push_back(new ImpSdXMLExpTransObj2DScale(rNew));
390 void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew)
392 if(!rNew.equalZero())
393 maList.push_back(new ImpSdXMLExpTransObj2DTranslate(rNew));
396 void SdXMLImExTransform2D::AddSkewX(double fNew)
398 if(fNew != 0.0)
399 maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fNew));
402 void SdXMLImExTransform2D::AddSkewY(double fNew)
404 if(fNew != 0.0)
405 maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fNew));
408 void SdXMLImExTransform2D::AddMatrix(const ::basegfx::B2DHomMatrix& rNew)
410 if(!rNew.isIdentity())
411 maList.push_back(new ImpSdXMLExpTransObj2DMatrix(rNew));
414 //////////////////////////////////////////////////////////////////////////////
415 // gen string for export
416 const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv)
418 OUString aNewString;
419 OUString aClosingBrace(sal_Unicode(')'));
420 OUString aEmptySpace(sal_Unicode(' '));
422 const sal_uInt32 nCount = maList.size();
423 for(sal_uInt32 a(0L); a < nCount; a++)
425 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
426 switch(pObj->mnType)
428 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
430 aNewString += OUString::createFromAscii("rotate (");
431 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate);
432 aNewString += aClosingBrace;
433 break;
435 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
437 aNewString += OUString::createFromAscii("scale (");
438 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getX());
439 aNewString += aEmptySpace;
440 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getY());
441 aNewString += aClosingBrace;
442 break;
444 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
446 aNewString += OUString::createFromAscii("translate (");
447 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getX(), true);
448 aNewString += aEmptySpace;
449 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getY(), true);
450 aNewString += aClosingBrace;
451 break;
453 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
455 aNewString += OUString::createFromAscii("skewX (");
456 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX);
457 aNewString += aClosingBrace;
458 break;
460 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
462 aNewString += OUString::createFromAscii("skewY (");
463 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY);
464 aNewString += aClosingBrace;
465 break;
467 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
469 aNewString += OUString::createFromAscii("matrix (");
471 // a
472 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 0));
473 aNewString += aEmptySpace;
475 // b
476 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 0));
477 aNewString += aEmptySpace;
479 // c
480 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 1));
481 aNewString += aEmptySpace;
483 // d
484 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 1));
485 aNewString += aEmptySpace;
487 // e
488 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 2), true);
489 aNewString += aEmptySpace;
491 // f
492 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 2), true);
494 aNewString += aClosingBrace;
495 break;
497 default :
499 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
500 break;
504 // if not the last entry, add one space to next tag
505 if(a + 1UL != maList.size())
507 aNewString += aEmptySpace;
511 // fill string form OUString
512 msString = aNewString;
514 return msString;
517 //////////////////////////////////////////////////////////////////////////////
518 // for Import: constructor with string, parses it and generates entries
519 SdXMLImExTransform2D::SdXMLImExTransform2D(const OUString& rNew, const SvXMLUnitConverter& rConv)
521 SetString(rNew, rConv);
524 //////////////////////////////////////////////////////////////////////////////
525 // sets new string, parses it and generates entries
526 void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
528 msString = rNew;
529 EmptyList();
531 if(msString.getLength())
533 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
534 const sal_Int32 nLen(aStr.getLength());
536 const OUString aString_rotate(OUString::createFromAscii("rotate"));
537 const OUString aString_scale(OUString::createFromAscii("scale"));
538 const OUString aString_translate(OUString::createFromAscii("translate"));
539 const OUString aString_skewX(OUString::createFromAscii("skewX"));
540 const OUString aString_skewY(OUString::createFromAscii("skewY"));
541 const OUString aString_matrix(OUString::createFromAscii("matrix"));
543 sal_Int32 nPos(0);
545 while(nPos < nLen)
547 // skip spaces
548 Imp_SkipSpaces(aStr, nPos, nLen);
550 // look for tag
551 if(nPos < nLen)
553 if(nPos == aStr.indexOf(aString_rotate, nPos))
555 double fValue(0.0);
556 nPos += 6;
557 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
558 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
559 if(fValue != 0.0)
560 maList.push_back(new ImpSdXMLExpTransObj2DRotate(fValue));
562 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
564 else if(nPos == aStr.indexOf(aString_scale, nPos))
566 ::basegfx::B2DTuple aValue(1.0, 1.0);
567 nPos += 5;
568 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
569 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
570 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
571 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
573 if(aValue.getX() != 1.0 || aValue.getY() != 1.0)
574 maList.push_back(new ImpSdXMLExpTransObj2DScale(aValue));
576 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
578 else if(nPos == aStr.indexOf(aString_translate, nPos))
580 ::basegfx::B2DTuple aValue;
581 nPos += 9;
582 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
583 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
584 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
585 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
587 if(!aValue.equalZero())
588 maList.push_back(new ImpSdXMLExpTransObj2DTranslate(aValue));
590 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
592 else if(nPos == aStr.indexOf(aString_skewX, nPos))
594 double fValue(0.0);
595 nPos += 5;
596 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
597 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
598 if(fValue != 0.0)
599 maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fValue));
601 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
603 else if(nPos == aStr.indexOf(aString_skewY, nPos))
605 double fValue(0.0);
606 nPos += 5;
607 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
608 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
609 if(fValue != 0.0)
610 maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fValue));
612 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
614 else if(nPos == aStr.indexOf(aString_matrix, nPos))
616 ::basegfx::B2DHomMatrix aValue;
618 nPos += 6;
619 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
621 // a
622 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
623 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
625 // b
626 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
627 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
629 // c
630 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
631 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
633 // d
634 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
635 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
637 // e
638 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true));
639 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
641 // f
642 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true));
643 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
645 if(!aValue.isIdentity())
646 maList.push_back(new ImpSdXMLExpTransObj2DMatrix(aValue));
648 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
650 else
652 nPos++;
659 void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans)
661 rFullTrans.identity();
663 const sal_uInt32 nCount = maList.size();
664 for(sal_uInt32 a(0L); a < nCount; a++)
666 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
667 switch(pObj->mnType)
669 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
671 // #i78696#
672 // mfRotate is mathematically wrong oriented since we export/import the angle
673 // values mirrored. This error is fixed in the API, but not yet in the FileFormat.
674 // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next
675 // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary
676 // to mirror the value here
677 rFullTrans.rotate(((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate * -1.0);
678 break;
680 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
682 const ::basegfx::B2DTuple& rScale = ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale;
683 rFullTrans.scale(rScale.getX(), rScale.getY());
684 break;
686 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
688 const ::basegfx::B2DTuple& rTranslate = ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate;
689 rFullTrans.translate(rTranslate.getX(), rTranslate.getY());
690 break;
692 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
694 rFullTrans.shearX(tan(((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX));
695 break;
697 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
699 rFullTrans.shearY(tan(((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY));
700 break;
702 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
704 rFullTrans *= ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix;
705 break;
707 default :
709 DBG_ERROR("SdXMLImExTransform2D: impossible entry!");
710 break;
716 //////////////////////////////////////////////////////////////////////////////
717 //////////////////////////////////////////////////////////////////////////////
718 // base class of all 3D transform objects
720 struct ImpSdXMLExpTransObj3DBase
722 sal_uInt16 mnType;
723 ImpSdXMLExpTransObj3DBase(sal_uInt16 nType)
724 : mnType(nType) {}
727 //////////////////////////////////////////////////////////////////////////////
728 // possible object types for 3D
730 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000
731 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001
732 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002
733 #define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003
734 #define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004
735 #define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005
737 //////////////////////////////////////////////////////////////////////////////
738 // classes of objects, different sizes
740 struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase
742 double mfRotateX;
743 ImpSdXMLExpTransObj3DRotateX(double fVal)
744 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {}
746 struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase
748 double mfRotateY;
749 ImpSdXMLExpTransObj3DRotateY(double fVal)
750 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {}
752 struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase
754 double mfRotateZ;
755 ImpSdXMLExpTransObj3DRotateZ(double fVal)
756 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {}
758 struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase
760 ::basegfx::B3DTuple maScale;
761 ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew)
762 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {}
764 struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase
766 ::basegfx::B3DTuple maTranslate;
767 ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew)
768 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {}
770 struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase
772 ::basegfx::B3DHomMatrix maMatrix;
773 ImpSdXMLExpTransObj3DMatrix(const ::basegfx::B3DHomMatrix& rNew)
774 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(rNew) {}
777 //////////////////////////////////////////////////////////////////////////////
778 //////////////////////////////////////////////////////////////////////////////
779 // delete all entries in list
781 void SdXMLImExTransform3D::EmptyList()
783 const sal_uInt32 nCount = maList.size();
784 for(sal_uInt32 a(0L); a < nCount; a++)
786 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
788 switch(pObj->mnType)
790 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
792 delete (ImpSdXMLExpTransObj3DRotateX*)pObj;
793 break;
795 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
797 delete (ImpSdXMLExpTransObj3DRotateY*)pObj;
798 break;
800 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
802 delete (ImpSdXMLExpTransObj3DRotateZ*)pObj;
803 break;
805 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
807 delete (ImpSdXMLExpTransObj3DScale*)pObj;
808 break;
810 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
812 delete (ImpSdXMLExpTransObj3DTranslate*)pObj;
813 break;
815 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
817 delete (ImpSdXMLExpTransObj3DMatrix*)pObj;
818 break;
820 default :
822 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
823 break;
828 maList.clear();
831 //////////////////////////////////////////////////////////////////////////////
832 // add members
834 void SdXMLImExTransform3D::AddRotateX(double fNew)
836 if(fNew != 0.0)
837 maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fNew));
840 void SdXMLImExTransform3D::AddRotateY(double fNew)
842 if(fNew != 0.0)
843 maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fNew));
846 void SdXMLImExTransform3D::AddRotateZ(double fNew)
848 if(fNew != 0.0)
849 maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fNew));
852 void SdXMLImExTransform3D::AddScale(const ::basegfx::B3DTuple& rNew)
854 if(1.0 != rNew.getX() || 1.0 != rNew.getY() || 1.0 != rNew.getZ())
855 maList.push_back(new ImpSdXMLExpTransObj3DScale(rNew));
858 void SdXMLImExTransform3D::AddTranslate(const ::basegfx::B3DTuple& rNew)
860 if(!rNew.equalZero())
861 maList.push_back(new ImpSdXMLExpTransObj3DTranslate(rNew));
864 void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew)
866 if(!rNew.isIdentity())
867 maList.push_back(new ImpSdXMLExpTransObj3DMatrix(rNew));
870 void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat)
872 ::basegfx::B3DHomMatrix aExportMatrix;
874 aExportMatrix.set(0, 0, xHomMat.Line1.Column1);
875 aExportMatrix.set(0, 1, xHomMat.Line1.Column2);
876 aExportMatrix.set(0, 2, xHomMat.Line1.Column3);
877 aExportMatrix.set(0, 3, xHomMat.Line1.Column4);
878 aExportMatrix.set(1, 0, xHomMat.Line2.Column1);
879 aExportMatrix.set(1, 1, xHomMat.Line2.Column2);
880 aExportMatrix.set(1, 2, xHomMat.Line2.Column3);
881 aExportMatrix.set(1, 3, xHomMat.Line2.Column4);
882 aExportMatrix.set(2, 0, xHomMat.Line3.Column1);
883 aExportMatrix.set(2, 1, xHomMat.Line3.Column2);
884 aExportMatrix.set(2, 2, xHomMat.Line3.Column3);
885 aExportMatrix.set(2, 3, xHomMat.Line3.Column4);
887 AddMatrix(aExportMatrix);
890 //////////////////////////////////////////////////////////////////////////////
891 // gen string for export
892 const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv)
894 OUString aNewString;
895 OUString aClosingBrace(sal_Unicode(')'));
896 OUString aEmptySpace(sal_Unicode(' '));
898 const sal_uInt32 nCount = maList.size();
899 for(sal_uInt32 a(0L); a < nCount; a++)
901 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
902 switch(pObj->mnType)
904 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
906 aNewString += OUString::createFromAscii("rotatex (");
907 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX);
908 aNewString += aClosingBrace;
909 break;
911 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
913 aNewString += OUString::createFromAscii("rotatey (");
914 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY);
915 aNewString += aClosingBrace;
916 break;
918 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
920 aNewString += OUString::createFromAscii("rotatez (");
921 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
922 aNewString += aClosingBrace;
923 break;
925 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
927 aNewString += OUString::createFromAscii("scale (");
928 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getX());
929 aNewString += aEmptySpace;
930 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getY());
931 aNewString += aEmptySpace;
932 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getZ());
933 aNewString += aClosingBrace;
934 break;
936 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
938 aNewString += OUString::createFromAscii("translate (");
939 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getX(), true);
940 aNewString += aEmptySpace;
941 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getY(), true);
942 aNewString += aEmptySpace;
943 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getZ(), true);
944 aNewString += aClosingBrace;
945 break;
947 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
949 aNewString += OUString::createFromAscii("matrix (");
951 // a
952 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 0));
953 aNewString += aEmptySpace;
955 // b
956 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 0));
957 aNewString += aEmptySpace;
959 // c
960 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 0));
961 aNewString += aEmptySpace;
963 // d
964 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 1));
965 aNewString += aEmptySpace;
967 // e
968 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 1));
969 aNewString += aEmptySpace;
971 // f
972 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 1));
973 aNewString += aEmptySpace;
975 // g
976 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 2));
977 aNewString += aEmptySpace;
979 // h
980 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 2));
981 aNewString += aEmptySpace;
983 // i
984 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 2));
985 aNewString += aEmptySpace;
987 // j
988 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 3), true);
989 aNewString += aEmptySpace;
991 // k
992 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 3), true);
993 aNewString += aEmptySpace;
995 // l
996 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 3), true);
998 aNewString += aClosingBrace;
999 break;
1001 default :
1003 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
1004 break;
1008 // if not the last entry, add one space to next tag
1009 if(a + 1UL != maList.size())
1011 aNewString += aEmptySpace;
1015 // fill string form OUString
1016 msString = aNewString;
1018 return msString;
1021 //////////////////////////////////////////////////////////////////////////////
1022 // for Import: constructor with string, parses it and generates entries
1023 SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv)
1025 SetString(rNew, rConv);
1028 //////////////////////////////////////////////////////////////////////////////
1029 // sets new string, parses it and generates entries
1030 void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
1032 msString = rNew;
1033 EmptyList();
1035 if(msString.getLength())
1037 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1038 const sal_Int32 nLen(aStr.getLength());
1040 const OUString aString_rotatex(OUString::createFromAscii("rotatex"));
1041 const OUString aString_rotatey(OUString::createFromAscii("rotatey"));
1042 const OUString aString_rotatez(OUString::createFromAscii("rotatez"));
1043 const OUString aString_scale(OUString::createFromAscii("scale"));
1044 const OUString aString_translate(OUString::createFromAscii("translate"));
1045 const OUString aString_matrix(OUString::createFromAscii("matrix"));
1047 sal_Int32 nPos(0);
1049 while(nPos < nLen)
1051 // skip spaces
1052 Imp_SkipSpaces(aStr, nPos, nLen);
1054 // look for tag
1055 if(nPos < nLen)
1057 if(nPos == aStr.indexOf(aString_rotatex, nPos))
1059 double fValue(0.0);
1061 nPos += 7;
1062 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1063 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1064 if(fValue != 0.0)
1065 maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fValue));
1067 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1069 else if(nPos == aStr.indexOf(aString_rotatey, nPos))
1071 double fValue(0.0);
1073 nPos += 7;
1074 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1075 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1076 if(fValue != 0.0)
1077 maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fValue));
1079 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1081 else if(nPos == aStr.indexOf(aString_rotatez, nPos))
1083 double fValue(0.0);
1085 nPos += 7;
1086 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1087 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1088 if(fValue != 0.0)
1089 maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fValue));
1091 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1093 else if(nPos == aStr.indexOf(aString_scale, nPos))
1095 ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0);
1097 nPos += 5;
1098 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1099 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
1100 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1101 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
1102 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1103 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ()));
1105 if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ())
1106 maList.push_back(new ImpSdXMLExpTransObj3DScale(aValue));
1108 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1110 else if(nPos == aStr.indexOf(aString_translate, nPos))
1112 ::basegfx::B3DTuple aValue;
1114 nPos += 9;
1115 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1116 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
1117 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1118 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
1119 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1120 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true));
1122 if(!aValue.equalZero())
1123 maList.push_back(new ImpSdXMLExpTransObj3DTranslate(aValue));
1125 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1127 else if(nPos == aStr.indexOf(aString_matrix, nPos))
1129 ::basegfx::B3DHomMatrix aValue;
1131 nPos += 6;
1132 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1134 // a
1135 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
1136 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1138 // b
1139 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
1140 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1142 // c
1143 aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0)));
1144 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1146 // d
1147 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
1148 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1150 // e
1151 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
1152 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1154 // f
1155 aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1)));
1156 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1158 // g
1159 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2)));
1160 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1162 // h
1163 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2)));
1164 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1166 // i
1167 aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2)));
1168 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1170 // j
1171 aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true));
1172 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1174 // k
1175 aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true));
1176 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1178 // l
1179 aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true));
1180 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1182 if(!aValue.isIdentity())
1183 maList.push_back(new ImpSdXMLExpTransObj3DMatrix(aValue));
1185 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1187 else
1189 nPos++;
1196 bool SdXMLImExTransform3D::GetFullHomogenTransform(com::sun::star::drawing::HomogenMatrix& xHomMat)
1198 ::basegfx::B3DHomMatrix aFullTransform;
1199 GetFullTransform(aFullTransform);
1201 if(!aFullTransform.isIdentity())
1203 xHomMat.Line1.Column1 = aFullTransform.get(0, 0);
1204 xHomMat.Line1.Column2 = aFullTransform.get(0, 1);
1205 xHomMat.Line1.Column3 = aFullTransform.get(0, 2);
1206 xHomMat.Line1.Column4 = aFullTransform.get(0, 3);
1208 xHomMat.Line2.Column1 = aFullTransform.get(1, 0);
1209 xHomMat.Line2.Column2 = aFullTransform.get(1, 1);
1210 xHomMat.Line2.Column3 = aFullTransform.get(1, 2);
1211 xHomMat.Line2.Column4 = aFullTransform.get(1, 3);
1213 xHomMat.Line3.Column1 = aFullTransform.get(2, 0);
1214 xHomMat.Line3.Column2 = aFullTransform.get(2, 1);
1215 xHomMat.Line3.Column3 = aFullTransform.get(2, 2);
1216 xHomMat.Line3.Column4 = aFullTransform.get(2, 3);
1218 xHomMat.Line4.Column1 = aFullTransform.get(3, 0);
1219 xHomMat.Line4.Column2 = aFullTransform.get(3, 1);
1220 xHomMat.Line4.Column3 = aFullTransform.get(3, 2);
1221 xHomMat.Line4.Column4 = aFullTransform.get(3, 3);
1223 return true;
1226 return false;
1229 void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans)
1231 rFullTrans.identity();
1233 const sal_uInt32 nCount = maList.size();
1234 for(sal_uInt32 a(0L); a < nCount; a++)
1236 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
1237 switch(pObj->mnType)
1239 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
1241 rFullTrans.rotate(((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX, 0.0, 0.0);
1242 break;
1244 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
1246 rFullTrans.rotate(0.0, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY, 0.0);
1247 break;
1249 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
1251 rFullTrans.rotate(0.0, 0.0, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
1252 break;
1254 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
1256 const ::basegfx::B3DTuple& rScale = ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale;
1257 rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ());
1258 break;
1260 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
1262 const ::basegfx::B3DTuple& rTranslate = ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate;
1263 rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
1264 break;
1266 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
1268 rFullTrans *= ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix;
1269 break;
1271 default :
1273 DBG_ERROR("SdXMLImExTransform3D: impossible entry!");
1274 break;
1280 //////////////////////////////////////////////////////////////////////////////
1281 //////////////////////////////////////////////////////////////////////////////
1283 SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX, sal_Int32 nY, sal_Int32 nW, sal_Int32 nH)
1284 : mnX( nX ),
1285 mnY( nY ),
1286 mnW( nW ),
1287 mnH( nH )
1291 // #100617# Asked vincent hardy: svg:viewBox values may be double precision.
1292 SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv)
1293 : msString(rNew),
1294 mnX( 0L ),
1295 mnY( 0L ),
1296 mnW( 1000L ),
1297 mnH( 1000L )
1299 if(msString.getLength())
1301 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1302 const sal_Int32 nLen(aStr.getLength());
1303 sal_Int32 nPos(0);
1305 // skip starting spaces
1306 Imp_SkipSpaces(aStr, nPos, nLen);
1308 // get mX, #100617# be prepared for doubles
1309 mnX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnX));
1311 // skip spaces and commas
1312 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1314 // get mY, #100617# be prepared for doubles
1315 mnY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnY));
1317 // skip spaces and commas
1318 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1320 // get mW, #100617# be prepared for doubles
1321 mnW = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnW));
1323 // skip spaces and commas
1324 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1326 // get mH, #100617# be prepared for doubles
1327 mnH = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnH));
1331 const OUString& SdXMLImExViewBox::GetExportString()
1333 OUString aNewString;
1334 OUString aEmptySpace(sal_Unicode(' '));
1336 Imp_PutNumberChar(aNewString, mnX);
1337 aNewString += aEmptySpace;
1339 Imp_PutNumberChar(aNewString, mnY);
1340 aNewString += aEmptySpace;
1342 Imp_PutNumberChar(aNewString, mnW);
1343 aNewString += aEmptySpace;
1345 Imp_PutNumberChar(aNewString, mnH);
1347 // set new string
1348 msString = aNewString;
1350 return msString;
1353 //////////////////////////////////////////////////////////////////////////////
1354 //////////////////////////////////////////////////////////////////////////////
1356 SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence* pPoints,
1357 const SdXMLImExViewBox& rViewBox,
1358 const awt::Point& rObjectPos,
1359 const awt::Size& rObjectSize,
1360 // #96328#
1361 const bool bClosed)
1362 : maPoly( 0L )
1364 DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExPointsElement(!)");
1366 // add polygon to string
1367 sal_Int32 nCnt(pPoints->getLength());
1369 // #104076# Convert to string only when at last one point included
1370 if(nCnt > 0)
1372 OUString aNewString;
1373 awt::Point* pArray = pPoints->getArray();
1375 // last point same? Ignore it.
1376 // #96328# ...but only when polygon is CLOSED
1377 if(bClosed && (pArray->X == (pArray + (nCnt - 1))->X) && (pArray->Y == (pArray + (nCnt - 1))->Y))
1378 nCnt--;
1380 // object size and ViewBox size different?
1381 bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1382 || rObjectSize.Height != rViewBox.GetHeight());
1383 bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1385 for(sal_Int32 a(0L); a < nCnt; a++)
1387 // prepare coordinates
1388 sal_Int32 nX( pArray->X - rObjectPos.X );
1389 sal_Int32 nY( pArray->Y - rObjectPos.Y );
1391 if(bScale && rObjectSize.Width && rObjectSize.Height)
1393 nX = (nX * rViewBox.GetWidth()) / rObjectSize.Width;
1394 nY = (nY * rViewBox.GetHeight()) / rObjectSize.Height;
1397 if(bTranslate)
1399 nX += rViewBox.GetX();
1400 nY += rViewBox.GetY();
1403 // X and comma
1404 Imp_PutNumberChar(aNewString, nX);
1405 aNewString += String(sal_Unicode(','));
1407 // Y and space (not for last)
1408 Imp_PutNumberChar(aNewString, nY);
1409 if(a + 1 != nCnt)
1410 aNewString += String(sal_Unicode(' '));
1412 // next point
1413 pArray++;
1416 // set new string
1417 msString = aNewString;
1421 // #100617# svg:polyline or svg:polygon values may be double precision.
1422 SdXMLImExPointsElement::SdXMLImExPointsElement(const OUString& rNew,
1423 const SdXMLImExViewBox& rViewBox,
1424 const awt::Point& rObjectPos,
1425 const awt::Size& rObjectSize,
1426 const SvXMLUnitConverter& rConv)
1427 : msString( rNew ),
1428 maPoly( 0L )
1430 // convert string to polygon
1431 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1432 const sal_Int32 nLen(aStr.getLength());
1433 sal_Int32 nPos(0);
1434 sal_Int32 nNumPoints(0L);
1436 // skip starting spaces
1437 Imp_SkipSpaces(aStr, nPos, nLen);
1439 // count points in first loop
1440 while(nPos < nLen)
1442 // skip number, #100617# be prepared for doubles
1443 Imp_SkipDouble(aStr, nPos, nLen);
1445 // skip spaces and commas
1446 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1448 // skip number, #100617# be prepared for doubles
1449 Imp_SkipDouble(aStr, nPos, nLen);
1451 // skip spaces and commas
1452 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1454 // one more point
1455 nNumPoints++;
1458 // second loop
1459 if(nNumPoints)
1461 nPos = 0L;
1462 maPoly.realloc(1L);
1463 drawing::PointSequence* pOuterSequence = maPoly.getArray();
1464 pOuterSequence->realloc(nNumPoints);
1465 awt::Point* pInnerSequence = pOuterSequence->getArray();
1467 // object size and ViewBox size different?
1468 bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1469 || rObjectSize.Height != rViewBox.GetHeight());
1470 bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1472 // skip starting spaces
1473 Imp_SkipSpaces(aStr, nPos, nLen);
1475 while(nPos < nLen)
1477 // prepare new parameter pair
1478 sal_Int32 nX(0L);
1479 sal_Int32 nY(0L);
1481 // get mX, #100617# be prepared for doubles
1482 nX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nX));
1484 // skip spaces and commas
1485 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1487 // get mY, #100617# be prepared for doubles
1488 nY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nY));
1490 // skip spaces and commas
1491 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1493 // prepare parameters
1494 if(bTranslate)
1496 nX -= rViewBox.GetX();
1497 nY -= rViewBox.GetY();
1500 if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight() )
1502 nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
1503 nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
1506 nX += rObjectPos.X;
1507 nY += rObjectPos.Y;
1509 // add new point
1510 *pInnerSequence = awt::Point( nX, nY );
1511 pInnerSequence++;
1516 //////////////////////////////////////////////////////////////////////////////
1517 //////////////////////////////////////////////////////////////////////////////
1519 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox)
1520 : mrViewBox( rViewBox ),
1521 mbIsClosed( false ),
1522 mbIsCurve( false ),
1523 mnLastX( 0L ),
1524 mnLastY( 0L ),
1525 maPoly( 0L ),
1526 maFlag( 0L )
1530 void Imp_GetPrevPos(awt::Point*& pPrevPos1,
1531 drawing::PolygonFlags& aPrevFlag1,
1532 const bool bClosed, awt::Point* pPoints,
1533 drawing::PolygonFlags* pFlags, const sal_Int32 nPos,
1534 const sal_Int32 nCnt, const sal_Int32 nAdd)
1536 if(bClosed)
1538 pPrevPos1 = pPoints + ((nPos + nCnt - nAdd) % nCnt);
1539 aPrevFlag1 = *(pFlags + ((nPos + nCnt - nAdd) % nCnt));
1541 else if(nPos > (nAdd - 1))
1543 pPrevPos1 = pPoints + (nPos - nAdd);
1544 aPrevFlag1 = *(pFlags + (nPos - nAdd));
1546 else
1547 pPrevPos1 = 0L;
1550 void Imp_PrepareCoorExport(sal_Int32& nX, sal_Int32& nY,
1551 const awt::Point* pPointArray, const awt::Point& rObjectPos,
1552 const awt::Size& rObjectSize, const SdXMLImExViewBox& mrViewBox,
1553 const bool bScale, const bool bTranslate)
1555 nX = pPointArray->X - rObjectPos.X;
1556 nY = pPointArray->Y - rObjectPos.Y;
1558 if(bScale && rObjectSize.Width && rObjectSize.Height )
1560 nX = (nX * mrViewBox.GetWidth()) / rObjectSize.Width;
1561 nY = (nY * mrViewBox.GetHeight()) / rObjectSize.Height;
1564 if(bTranslate)
1566 nX += mrViewBox.GetX();
1567 nY += mrViewBox.GetY();
1571 //#define TEST_QUADRATIC_CURVES
1572 #ifdef TEST_QUADRATIC_CURVES
1573 // To be able to test quadratic curve code: The code concerning to
1574 // bDoTestHere can be used (see below). Construct shapes which have their control
1575 // points on equal coordinates. When these are written, they can be
1576 // forced to create correct 'Q' and 'T' statements using this flag.
1577 // These may then be tested for import/exporting.
1578 static bool bDoTestHere(true);
1579 #endif // TEST_QUADRATIC_CURVES
1581 void SdXMLImExSvgDElement::AddPolygon(
1582 drawing::PointSequence* pPoints,
1583 drawing::FlagSequence* pFlags,
1584 const awt::Point& rObjectPos,
1585 const awt::Size& rObjectSize,
1586 bool bClosed, bool bRelative)
1588 DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExSvgDElement(!)");
1590 sal_Int32 nCnt(pPoints->getLength());
1592 // #104076# Convert to string only when at last one point included
1593 if(nCnt > 0)
1595 // append polygon to string
1596 OUString aNewString;
1597 sal_Unicode aLastCommand = ' ';
1598 awt::Point* pPointArray = pPoints->getArray();
1600 // are the flags used at all? If not forget about them
1601 if(pFlags)
1603 sal_Int32 nFlagCnt(pFlags->getLength());
1605 if(nFlagCnt)
1607 bool bFlagsUsed(false);
1608 drawing::PolygonFlags* pFlagArray = pFlags->getArray();
1610 for(sal_Int32 a(0); !bFlagsUsed && a < nFlagCnt; a++)
1611 if(drawing::PolygonFlags_NORMAL != *pFlagArray++)
1612 bFlagsUsed = true;
1614 if(!bFlagsUsed)
1615 pFlags = 0L;
1617 else
1619 pFlags = 0L;
1623 // object size and ViewBox size different?
1624 bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
1625 || rObjectSize.Height != mrViewBox.GetHeight());
1626 bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
1628 // #87202# rework of point reduction:
1629 // Test for Last point same -> closed, ignore last point. Take
1630 // some more circumstances in account when looking at curve segments.
1631 drawing::PolygonFlags* pFlagArray = (pFlags) ? pFlags->getArray() : 0L;
1632 if((pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y))
1634 if(pFlags)
1636 // point needs to be ignored if point before it is
1637 // NO control point. Else the last point is needed
1638 // for exporting the last segment of the curve. That means
1639 // that the last and the first point will be saved double,
1640 // but SVG does not support a better solution here.
1641 if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2)))
1643 nCnt--;
1646 else
1648 // no curve, ignore last point
1649 nCnt--;
1653 // bezier poly, handle curves
1654 bool bDidWriteStart(false);
1656 for(sal_Int32 a(0L); a < nCnt; a++)
1658 if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray)
1660 bool bDidWriteAsCurve(false);
1662 if(bDidWriteStart)
1664 if(pFlags)
1666 // real curve point, get previous to see if it's a control point
1667 awt::Point* pPrevPos1;
1668 drawing::PolygonFlags aPrevFlag1;
1670 Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(),
1671 pFlags->getArray(), a, nCnt, 1);
1673 if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1)
1675 // get previous2 to see if it's a control point, too
1676 awt::Point* pPrevPos2;
1677 drawing::PolygonFlags aPrevFlag2;
1679 Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(),
1680 pFlags->getArray(), a, nCnt, 2);
1682 if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2)
1684 // get previous3 to see if it's a curve point and if,
1685 // if it is fully symmetric or not
1686 awt::Point* pPrevPos3;
1687 drawing::PolygonFlags aPrevFlag3;
1689 Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(),
1690 pFlags->getArray(), a, nCnt, 3);
1692 if(pPrevPos3)
1694 // prepare coordinates
1695 sal_Int32 nX, nY;
1697 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
1698 mrViewBox, bScale, bTranslate);
1700 // #100617# test if this curve segment may be written as
1701 // a quadratic bezier
1702 // That's the case if both control points are in the same place
1703 // when they are prolonged to the common quadratic control point
1704 // Left: P = (3P1 - P0) / 2
1705 // Right: P = (3P2 - P3) / 2
1706 bool bIsQuadratic(false);
1707 const bool bEnableSaveQuadratic(false);
1709 sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0));
1710 sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0));
1711 sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0));
1712 sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0));
1713 sal_Int32 nDist(0);
1715 if(nPX_L != nPX_R)
1717 nDist += abs(nPX_L - nPX_R);
1720 if(nPY_L != nPY_R)
1722 nDist += abs(nPY_L - nPY_R);
1725 if(nDist <= BORDER_INTEGERS_ARE_EQUAL)
1727 if(bEnableSaveQuadratic)
1729 bIsQuadratic = true;
1733 #ifdef TEST_QUADRATIC_CURVES
1734 if(bDoTestHere)
1736 bIsQuadratic = false;
1738 if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y)
1739 bIsQuadratic = true;
1741 #endif // TEST_QUADRATIC_CURVES
1743 if(bIsQuadratic)
1745 #ifdef TEST_QUADRATIC_CURVES
1746 if(bDoTestHere)
1748 bool bPrevPointIsSymmetric(false);
1750 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1752 // get previous4 to see if it's a control point
1753 awt::Point* pPrevPos4;
1754 drawing::PolygonFlags aPrevFlag4;
1756 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1757 pFlags->getArray(), a, nCnt, 4);
1759 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1761 // okay, prevPos3 is symmetric (c2) and prevPos4
1762 // is existing control point, the 's' statement can be used
1763 bPrevPointIsSymmetric = true;
1767 if(bPrevPointIsSymmetric)
1769 // write a shorthand/smooth quadratic curveto entry (T)
1770 if(bRelative)
1772 if(aLastCommand != sal_Unicode('t'))
1773 aNewString += OUString(sal_Unicode('t'));
1775 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1776 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1778 aLastCommand = sal_Unicode('t');
1780 else
1782 if(aLastCommand != sal_Unicode('T'))
1783 aNewString += OUString(sal_Unicode('T'));
1785 Imp_PutNumberCharWithSpace(aNewString, nX);
1786 Imp_PutNumberCharWithSpace(aNewString, nY);
1788 aLastCommand = sal_Unicode('T');
1791 else
1793 // prepare coordinates
1794 sal_Int32 nX1, nY1;
1796 Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize,
1797 mrViewBox, bScale, bTranslate);
1799 // write a quadratic curveto entry (Q)
1800 if(bRelative)
1802 if(aLastCommand != sal_Unicode('q'))
1803 aNewString += OUString(sal_Unicode('q'));
1805 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1806 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1807 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1808 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1810 aLastCommand = sal_Unicode('q');
1812 else
1814 if(aLastCommand != sal_Unicode('Q'))
1815 aNewString += OUString(sal_Unicode('Q'));
1817 Imp_PutNumberCharWithSpace(aNewString, nX1);
1818 Imp_PutNumberCharWithSpace(aNewString, nY1);
1819 Imp_PutNumberCharWithSpace(aNewString, nX);
1820 Imp_PutNumberCharWithSpace(aNewString, nY);
1822 aLastCommand = sal_Unicode('Q');
1826 else
1828 #endif // TEST_QUADRATIC_CURVES
1829 awt::Point aNewPoint(nPX_L, nPY_L);
1830 bool bPrevPointIsSmooth(false);
1832 if(drawing::PolygonFlags_SMOOTH == aPrevFlag3)
1834 // get previous4 to see if it's a control point
1835 awt::Point* pPrevPos4;
1836 drawing::PolygonFlags aPrevFlag4;
1838 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1839 pFlags->getArray(), a, nCnt, 4);
1841 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1843 // okay, prevPos3 is smooth (c1) and prevPos4
1844 // is existing control point. Test if it's even symmetric
1845 // and thus the 'T' statement may be used.
1846 ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y);
1847 ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y);
1848 bool bSameLength(false);
1849 bool bSameDirection(false);
1851 // get vector values
1852 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
1854 if(bSameLength && bSameDirection)
1855 bPrevPointIsSmooth = true;
1859 if(bPrevPointIsSmooth)
1861 // write a shorthand/smooth quadratic curveto entry (T)
1862 if(bRelative)
1864 if(aLastCommand != sal_Unicode('t'))
1865 aNewString += String(sal_Unicode('t'));
1867 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1868 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1870 aLastCommand = sal_Unicode('t');
1872 else
1874 if(aLastCommand != sal_Unicode('T'))
1875 aNewString += String(sal_Unicode('T'));
1877 Imp_PutNumberCharWithSpace(aNewString, nX);
1878 Imp_PutNumberCharWithSpace(aNewString, nY);
1880 aLastCommand = sal_Unicode('T');
1883 else
1885 // prepare coordinates
1886 sal_Int32 nX1, nY1;
1888 Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize,
1889 mrViewBox, bScale, bTranslate);
1891 // write a quadratic curveto entry (Q)
1892 if(bRelative)
1894 if(aLastCommand != sal_Unicode('q'))
1895 aNewString += String(sal_Unicode('q'));
1897 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1898 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1899 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1900 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1902 aLastCommand = sal_Unicode('q');
1904 else
1906 if(aLastCommand != sal_Unicode('Q'))
1907 aNewString += String(sal_Unicode('Q'));
1909 Imp_PutNumberCharWithSpace(aNewString, nX1);
1910 Imp_PutNumberCharWithSpace(aNewString, nY1);
1911 Imp_PutNumberCharWithSpace(aNewString, nX);
1912 Imp_PutNumberCharWithSpace(aNewString, nY);
1914 aLastCommand = sal_Unicode('Q');
1917 #ifdef TEST_QUADRATIC_CURVES
1919 #endif // TEST_QUADRATIC_CURVES
1921 else
1923 bool bPrevPointIsSymmetric(false);
1925 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1927 // get previous4 to see if it's a control point
1928 awt::Point* pPrevPos4;
1929 drawing::PolygonFlags aPrevFlag4;
1931 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1932 pFlags->getArray(), a, nCnt, 4);
1934 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1936 // okay, prevPos3 is symmetric (c2) and prevPos4
1937 // is existing control point, the 's' statement can be used
1938 bPrevPointIsSymmetric = true;
1942 // prepare coordinates
1943 sal_Int32 nX2, nY2;
1945 Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize,
1946 mrViewBox, bScale, bTranslate);
1948 if(bPrevPointIsSymmetric)
1950 // write a shorthand/smooth curveto entry (S)
1951 if(bRelative)
1953 if(aLastCommand != sal_Unicode('s'))
1954 aNewString += String(sal_Unicode('s'));
1956 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1957 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1958 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1959 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1961 aLastCommand = sal_Unicode('s');
1963 else
1965 if(aLastCommand != sal_Unicode('S'))
1966 aNewString += String(sal_Unicode('S'));
1968 Imp_PutNumberCharWithSpace(aNewString, nX2);
1969 Imp_PutNumberCharWithSpace(aNewString, nY2);
1970 Imp_PutNumberCharWithSpace(aNewString, nX);
1971 Imp_PutNumberCharWithSpace(aNewString, nY);
1973 aLastCommand = sal_Unicode('S');
1976 else
1978 // prepare coordinates
1979 sal_Int32 nX1, nY1;
1981 Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize,
1982 mrViewBox, bScale, bTranslate);
1984 // write a curveto entry (C)
1985 if(bRelative)
1987 if(aLastCommand != sal_Unicode('c'))
1988 aNewString += String(sal_Unicode('c'));
1990 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1991 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1992 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1993 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1994 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1995 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1997 aLastCommand = sal_Unicode('c');
1999 else
2001 if(aLastCommand != sal_Unicode('C'))
2002 aNewString += String(sal_Unicode('C'));
2004 Imp_PutNumberCharWithSpace(aNewString, nX1);
2005 Imp_PutNumberCharWithSpace(aNewString, nY1);
2006 Imp_PutNumberCharWithSpace(aNewString, nX2);
2007 Imp_PutNumberCharWithSpace(aNewString, nY2);
2008 Imp_PutNumberCharWithSpace(aNewString, nX);
2009 Imp_PutNumberCharWithSpace(aNewString, nY);
2011 aLastCommand = sal_Unicode('C');
2016 // remember that current point IS written
2017 bDidWriteAsCurve = true;
2019 // remember new last position
2020 mnLastX = nX;
2021 mnLastY = nY;
2028 if(!bDidWriteAsCurve)
2030 // current point not yet written, prepare coordinates
2031 sal_Int32 nX, nY;
2033 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
2034 mrViewBox, bScale, bTranslate);
2036 if(bDidWriteStart)
2038 // write as normal point
2039 if(mnLastX == nX)
2041 if(bRelative)
2043 if(aLastCommand != sal_Unicode('v'))
2044 aNewString += String(sal_Unicode('v'));
2046 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2048 aLastCommand = sal_Unicode('v');
2050 else
2052 if(aLastCommand != sal_Unicode('V'))
2053 aNewString += String(sal_Unicode('V'));
2055 Imp_PutNumberCharWithSpace(aNewString, nY);
2057 aLastCommand = sal_Unicode('V');
2060 else if(mnLastY == nY)
2062 if(bRelative)
2064 if(aLastCommand != sal_Unicode('h'))
2065 aNewString += String(sal_Unicode('h'));
2067 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2069 aLastCommand = sal_Unicode('h');
2071 else
2073 if(aLastCommand != sal_Unicode('H'))
2074 aNewString += String(sal_Unicode('H'));
2076 Imp_PutNumberCharWithSpace(aNewString, nX);
2078 aLastCommand = sal_Unicode('H');
2081 else
2083 if(bRelative)
2085 if(aLastCommand != sal_Unicode('l'))
2086 aNewString += String(sal_Unicode('l'));
2088 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2089 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2091 aLastCommand = sal_Unicode('l');
2093 else
2095 if(aLastCommand != sal_Unicode('L'))
2096 aNewString += String(sal_Unicode('L'));
2098 Imp_PutNumberCharWithSpace(aNewString, nX);
2099 Imp_PutNumberCharWithSpace(aNewString, nY);
2101 aLastCommand = sal_Unicode('L');
2105 else
2107 // write as start point
2108 if(bRelative)
2110 aNewString += String(sal_Unicode('m'));
2112 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2113 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2115 aLastCommand = sal_Unicode('l');
2117 else
2119 aNewString += String(sal_Unicode('M'));
2121 Imp_PutNumberCharWithSpace(aNewString, nX);
2122 Imp_PutNumberCharWithSpace(aNewString, nY);
2124 aLastCommand = sal_Unicode('L');
2127 // remember start written
2128 bDidWriteStart = true;
2131 // remember new last position
2132 mnLastX = nX;
2133 mnLastY = nY;
2137 // next point
2138 pPointArray++;
2139 pFlagArray++;
2142 // close path if closed poly
2143 if(bClosed)
2145 if(bRelative)
2146 aNewString += String(sal_Unicode('z'));
2147 else
2148 aNewString += String(sal_Unicode('Z'));
2151 // append new string
2152 msString += aNewString;
2156 // #100617# Linear double reader
2157 double Imp_ImportDoubleAndSpaces(
2158 double fRetval, const OUString& rStr, sal_Int32& rPos,
2159 const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2161 fRetval = Imp_GetDoubleChar(rStr, rPos, nLen, rConv, fRetval);
2162 Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2163 return fRetval;
2166 // #100617# Allow to read doubles, too. This will need to be changed to
2167 // the usage of Imp_ImportDoubleAndSpaces(...). For now, this is sufficient
2168 // since the interface cannot transport doubles.
2169 sal_Int32 Imp_ImportNumberAndSpaces(
2170 sal_Int32 nRetval, const OUString& rStr, sal_Int32& rPos,
2171 const sal_Int32 nLen, const SvXMLUnitConverter& rConv)
2173 nRetval = FRound(Imp_ImportDoubleAndSpaces(double(nRetval), rStr, rPos, nLen, rConv));
2174 Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
2175 return nRetval;
2178 void Imp_PrepareCoorImport(sal_Int32& nX, sal_Int32& nY,
2179 const awt::Point& rObjectPos, const awt::Size& rObjectSize,
2180 const SdXMLImExViewBox& rViewBox, const bool bScale, const bool bTranslate)
2182 if(bTranslate)
2184 nX -= rViewBox.GetX();
2185 nY -= rViewBox.GetY();
2188 if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight())
2190 nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
2191 nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
2194 nX += rObjectPos.X;
2195 nY += rObjectPos.Y;
2198 void Imp_AddExportPoints(sal_Int32 nX, sal_Int32 nY,
2199 awt::Point* pPoints, drawing::PolygonFlags* pFlags,
2200 const sal_Int32 nInnerIndex,
2201 drawing::PolygonFlags eFlag)
2203 if(pPoints)
2204 pPoints[nInnerIndex] = awt::Point( nX, nY );
2206 if(pFlags)
2207 pFlags[nInnerIndex] = eFlag;
2210 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection)
2212 const sal_Int32 nLen1(FRound(aVec1.getLength()));
2213 const sal_Int32 nLen2(FRound(aVec2.getLength()));
2214 aVec1.normalize();
2215 aVec2.normalize();
2216 aVec1 += aVec2;
2217 const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0)));
2219 bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL);
2220 bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL);
2223 void Imp_CorrectPolygonFlag(const sal_uInt32 nInnerIndex, const awt::Point* const pInnerSequence,
2224 drawing::PolygonFlags* const pInnerFlags, const sal_Int32 nX1, const sal_Int32 nY1)
2226 if(nInnerIndex)
2228 const awt::Point aPPrev1 = pInnerSequence[nInnerIndex - 1];
2230 if(nInnerIndex > 1)
2232 const awt::Point aPPrev2 = pInnerSequence[nInnerIndex - 2];
2233 const drawing::PolygonFlags aFPrev2 = pInnerFlags[nInnerIndex - 2];
2234 ::basegfx::B2DVector aVec1(aPPrev2.X - aPPrev1.X, aPPrev2.Y - aPPrev1.Y);
2235 ::basegfx::B2DVector aVec2(nX1 - aPPrev1.X, nY1 - aPPrev1.Y);
2236 bool bSameLength(false);
2237 bool bSameDirection(false);
2239 // get vector values
2240 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
2242 if(drawing::PolygonFlags_CONTROL == aFPrev2)
2244 // point before is a control point
2245 if(bSameDirection)
2247 if(bSameLength)
2249 // set to PolygonFlags_SYMMETRIC
2250 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2252 else
2254 // set to PolygonFlags_SMOOTH
2255 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2258 else
2260 // set to PolygonFlags_NORMAL
2261 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2264 else
2266 // point before is a simple curve point
2267 if(bSameDirection)
2269 // set to PolygonFlags_SMOOTH
2270 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2272 else
2274 // set to PolygonFlags_NORMAL
2275 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2279 else
2281 // no point before starpoint, set type to PolygonFlags_NORMAL
2282 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL;
2287 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew,
2288 const SdXMLImExViewBox& rViewBox,
2289 const awt::Point& rObjectPos,
2290 const awt::Size& rObjectSize,
2291 const SvXMLUnitConverter& rConv)
2292 : msString( rNew ),
2293 mrViewBox( rViewBox ),
2294 mbIsClosed( false ),
2295 mbIsCurve( false ),
2296 mnLastX( 0L ),
2297 mnLastY( 0L ),
2298 maPoly( 0L ),
2299 maFlag( 0L )
2301 // convert string to polygon
2302 const OUString aStr(msString.getStr(), msString.getLength());
2303 const sal_Int32 nLen(aStr.getLength());
2304 sal_Int32 nPos(0);
2305 sal_Int32 nNumPolys(0L);
2306 bool bEllipticalArc(false);
2308 // object size and ViewBox size different?
2309 bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
2310 || rObjectSize.Height != mrViewBox.GetHeight());
2311 bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
2313 // first loop: count polys and get flags
2314 Imp_SkipSpaces(aStr, nPos, nLen);
2316 while(nPos < nLen)
2318 switch(aStr[nPos++])
2320 case 'Z' :
2321 case 'z' :
2323 break;
2325 case 'M' :
2326 case 'm' :
2328 nNumPolys++;
2329 break;
2331 case 'S' :
2332 case 's' :
2333 case 'C' :
2334 case 'c' :
2335 case 'Q' :
2336 case 'q' :
2337 case 'T' :
2338 case 't' :
2340 mbIsCurve = true;
2341 break;
2343 case 'L' :
2344 case 'l' :
2345 case 'H' :
2346 case 'h' :
2347 case 'V' :
2348 case 'v' :
2350 // normal, interpreted values. All okay.
2351 break;
2353 case 'A' :
2354 case 'a' :
2356 // Not yet interpreted value.
2357 bEllipticalArc = true;
2358 break;
2363 DBG_ASSERT(!bEllipticalArc, "XMLIMP: non-interpreted tags in svg:d element!");
2365 if(nNumPolys)
2367 // alloc arrays
2368 maPoly.realloc(nNumPolys);
2369 if(IsCurve())
2370 maFlag.realloc(nNumPolys);
2372 // get outer sequences
2373 drawing::PointSequence* pOuterSequence = maPoly.getArray();
2374 drawing::FlagSequence* pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2376 // prepare new loop, count
2377 sal_uInt32 nPointCount(0L);
2378 nPos = 0;
2379 Imp_SkipSpaces(aStr, nPos, nLen);
2381 // #104076# reset closed flag for next to be started polygon
2382 mbIsClosed = false;
2384 while(nPos < nLen)
2386 switch(aStr[nPos])
2388 case 'z' :
2389 case 'Z' :
2391 nPos++;
2392 Imp_SkipSpaces(aStr, nPos, nLen);
2394 // #104076# remember closed state of current polygon
2395 mbIsClosed = true;
2397 break;
2399 case 'm' :
2400 case 'M' :
2402 // new poly starts, end-process current poly
2403 if(nPointCount)
2405 // #104076# If this partial polygon is closed, use one more point
2406 // to represent that
2407 if(mbIsClosed)
2409 nPointCount++;
2412 pOuterSequence->realloc(nPointCount);
2413 pOuterSequence++;
2415 if(pOuterFlags)
2417 pOuterFlags->realloc(nPointCount);
2418 pOuterFlags++;
2421 // reset point count for next polygon
2422 nPointCount = 0L;
2425 // #104076# reset closed flag for next to be started polygon
2426 mbIsClosed = false;
2428 // NO break, continue in next case
2430 case 'L' :
2431 case 'l' :
2433 nPos++;
2434 Imp_SkipSpaces(aStr, nPos, nLen);
2436 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2438 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2439 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2440 nPointCount++;
2442 break;
2444 case 'H' :
2445 case 'h' :
2446 case 'V' :
2447 case 'v' :
2449 nPos++;
2450 Imp_SkipSpaces(aStr, nPos, nLen);
2452 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2454 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2455 nPointCount++;
2457 break;
2459 case 'S' :
2460 case 's' :
2462 nPos++;
2463 Imp_SkipSpaces(aStr, nPos, nLen);
2465 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2467 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2468 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2469 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2470 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2471 nPointCount += 3;
2473 break;
2475 case 'C' :
2476 case 'c' :
2478 nPos++;
2479 Imp_SkipSpaces(aStr, nPos, nLen);
2481 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2483 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2484 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2485 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2486 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2487 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2488 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2489 nPointCount += 3;
2491 break;
2494 // #100617# quadratic beziers, supported as cubic ones
2495 case 'Q' :
2496 case 'q' :
2498 nPos++;
2499 Imp_SkipSpaces(aStr, nPos, nLen);
2501 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2503 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2504 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2505 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2506 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2508 // use three points since quadratic is imported as cubic
2509 nPointCount += 3;
2511 break;
2514 // #100617# relative quadratic beziers, supported as cubic ones
2515 case 'T' :
2516 case 't' :
2518 nPos++;
2519 Imp_SkipSpaces(aStr, nPos, nLen);
2521 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2523 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2524 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2526 // use three points since quadratic is imported as cubic
2527 nPointCount += 3;
2529 break;
2532 // #100617# not yet supported: elliptical arc
2533 case 'A' :
2534 case 'a' :
2536 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2537 nPos++;
2538 Imp_SkipSpaces(aStr, nPos, nLen);
2540 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2542 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2543 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2544 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2545 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2546 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
2547 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2548 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
2550 break;
2553 default:
2555 nPos++;
2556 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
2557 break;
2562 // alloc last poly (when points used)
2563 if(nPointCount)
2565 // #104076# If this partial polygon is closed, use one more point
2566 // to represent that
2567 if(mbIsClosed)
2569 nPointCount++;
2572 pOuterSequence->realloc(nPointCount);
2573 pOuterSequence++;
2575 if(pOuterFlags)
2577 pOuterFlags->realloc(nPointCount);
2578 pOuterFlags++;
2582 // set pointers back
2583 pOuterSequence = maPoly.getArray();
2584 pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L;
2585 awt::Point* pNotSoInnerSequence = 0L;
2586 drawing::PolygonFlags* pNotSoInnerFlags = 0L;
2587 sal_uInt32 nInnerIndex(0L);
2589 // prepare new loop, read points
2590 nPos = 0;
2591 Imp_SkipSpaces(aStr, nPos, nLen);
2593 // #104076# reset closed flag for next to be started polygon
2594 mbIsClosed = false;
2596 while(nPos < nLen)
2598 bool bRelative(false);
2600 switch(aStr[nPos])
2602 case 'z' :
2603 case 'Z' :
2605 nPos++;
2606 Imp_SkipSpaces(aStr, nPos, nLen);
2608 // #104076# remember closed state of current polygon
2609 mbIsClosed = true;
2611 // closed: add first point again
2612 // sal_Int32 nX(pInnerSequence[0].X);
2613 // sal_Int32 nY(pInnerSequence[0].Y);
2614 // Imp_AddExportPoints(nX, nY, pInnerSequence, pInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2616 break;
2619 case 'm' :
2621 bRelative = true;
2623 case 'M' :
2625 // #104076# end-process current poly
2626 if(mbIsClosed)
2628 if(pNotSoInnerSequence)
2630 // closed: add first point again
2631 sal_Int32 nX(pNotSoInnerSequence[0].X);
2632 sal_Int32 nY(pNotSoInnerSequence[0].Y);
2633 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2636 // reset closed flag for next to be started polygon
2637 mbIsClosed = false;
2640 // next poly
2641 pNotSoInnerSequence = pOuterSequence->getArray();
2642 pOuterSequence++;
2644 if(pOuterFlags)
2646 pNotSoInnerFlags = pOuterFlags->getArray();
2647 pOuterFlags++;
2650 nInnerIndex = 0L;
2652 nPos++;
2653 Imp_SkipSpaces(aStr, nPos, nLen);
2655 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2657 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2658 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2660 if(bRelative)
2662 nX += mnLastX;
2663 nY += mnLastY;
2666 // set last position
2667 mnLastX = nX;
2668 mnLastY = nY;
2670 // calc transform and add point and flag
2671 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2672 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2674 break;
2677 case 'l' :
2679 bRelative = true;
2681 case 'L' :
2683 nPos++;
2684 Imp_SkipSpaces(aStr, nPos, nLen);
2686 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2688 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2689 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2691 if(bRelative)
2693 nX += mnLastX;
2694 nY += mnLastY;
2697 // set last position
2698 mnLastX = nX;
2699 mnLastY = nY;
2701 // calc transform and add point and flag
2702 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2703 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2705 break;
2708 case 'h' :
2710 bRelative = true;
2712 case 'H' :
2714 nPos++;
2715 Imp_SkipSpaces(aStr, nPos, nLen);
2717 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2719 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2720 sal_Int32 nY(mnLastY);
2722 if(bRelative)
2723 nX += mnLastX;
2725 // set last position
2726 mnLastX = nX;
2728 // calc transform and add point and flag
2729 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2730 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2732 break;
2735 case 'v' :
2737 bRelative = true;
2739 case 'V' :
2741 nPos++;
2742 Imp_SkipSpaces(aStr, nPos, nLen);
2744 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2746 sal_Int32 nX(mnLastX);
2747 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2749 if(bRelative)
2750 nY += mnLastY;
2752 // set last position
2753 mnLastY = nY;
2755 // calc transform and add point and flag
2756 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2757 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
2759 break;
2762 case 's' :
2764 bRelative = true;
2766 case 'S' :
2768 nPos++;
2769 Imp_SkipSpaces(aStr, nPos, nLen);
2771 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2773 sal_Int32 nX1;
2774 sal_Int32 nY1;
2775 sal_Int32 nX2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2776 sal_Int32 nY2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2777 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2778 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2780 if(bRelative)
2782 nX2 += mnLastX;
2783 nY2 += mnLastY;
2784 nX += mnLastX;
2785 nY += mnLastY;
2788 // set last position
2789 mnLastX = nX;
2790 mnLastY = nY;
2792 // calc transform for new points
2793 Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2794 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2796 // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2797 // and the Point X1,Y1 can be constructed by mirroring the point before it.
2798 nX1 = nX2;
2799 nY1 = nY2;
2800 if(nInnerIndex)
2802 awt::Point aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2804 if(nInnerIndex > 1)
2806 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2807 nX1 = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2808 nY1 = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2811 // set curve point to symmetric
2812 pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC;
2815 // add calculated control point
2816 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2818 // add new points and set flags
2819 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2820 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2822 break;
2825 case 'c' :
2827 bRelative = true;
2829 case 'C' :
2831 nPos++;
2832 Imp_SkipSpaces(aStr, nPos, nLen);
2834 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2836 sal_Int32 nX1(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2837 sal_Int32 nY1(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2838 sal_Int32 nX2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2839 sal_Int32 nY2(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2840 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2841 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2843 if(bRelative)
2845 nX1 += mnLastX;
2846 nY1 += mnLastY;
2847 nX2 += mnLastX;
2848 nY2 += mnLastY;
2849 nX += mnLastX;
2850 nY += mnLastY;
2853 // set last position
2854 mnLastX = nX;
2855 mnLastY = nY;
2857 // calc transform for new points
2858 Imp_PrepareCoorImport(nX1, nY1, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2859 Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2860 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2862 // correct polygon flag for previous point
2863 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2865 // add new points and set flags
2866 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2867 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2868 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2870 break;
2873 // #100617# quadratic beziers are imported as cubic
2874 case 'q' :
2876 bRelative = true;
2878 case 'Q' :
2880 nPos++;
2881 Imp_SkipSpaces(aStr, nPos, nLen);
2883 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2885 sal_Int32 nXX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2886 sal_Int32 nYY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2887 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2888 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2890 if(bRelative)
2892 nXX += mnLastX;
2893 nYY += mnLastY;
2894 nX += mnLastX;
2895 nY += mnLastY;
2898 // set last position
2899 mnLastX = nX;
2900 mnLastY = nY;
2902 // calc transform for new points
2903 Imp_PrepareCoorImport(nXX, nYY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2904 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2906 // calculate X1,X2
2907 awt::Point aPPrev1 = (nInnerIndex) ? pNotSoInnerSequence[nInnerIndex-1] : pNotSoInnerSequence[0];
2908 sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2909 sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2910 sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2911 sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2913 // correct polygon flag for previous point
2914 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2916 // add new points and set flags
2917 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2918 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2919 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2921 break;
2924 // #100617# relative quadratic beziers are imported as cubic
2925 case 't' :
2927 bRelative = true;
2929 case 'T' :
2931 nPos++;
2932 Imp_SkipSpaces(aStr, nPos, nLen);
2934 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
2936 sal_Int32 nXX;
2937 sal_Int32 nYY;
2938 sal_Int32 nX(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2939 sal_Int32 nY(Imp_ImportNumberAndSpaces(0L, aStr, nPos, nLen, rConv));
2941 if(bRelative)
2943 nX += mnLastX;
2944 nY += mnLastY;
2947 // set last position
2948 mnLastX = nX;
2949 mnLastY = nY;
2951 // calc transform for new points
2952 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate);
2954 // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC
2955 // and the Point X1,Y1 can be constructed by mirroring the point before it.
2956 nXX = nX;
2957 nYY = nY;
2958 awt::Point aPPrev1 = pNotSoInnerSequence[0];
2960 if(nInnerIndex)
2962 aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1];
2964 if(nInnerIndex > 1)
2966 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2];
2967 nXX = aPPrev1.X -(aPPrev2.X - aPPrev1.X);
2968 nYY = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y);
2971 // set curve point to smooth here, since length
2972 // is changed and thus only c1 can be used.
2973 pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH;
2976 // calculate X1,X2
2977 sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0);
2978 sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0);
2979 sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0);
2980 sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0);
2982 // correct polygon flag for previous point
2983 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1);
2985 // add new points and set flags
2986 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2987 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL);
2988 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH);
2990 break;
2993 // #100617# not yet supported: elliptical arc
2994 case 'A' :
2995 case 'a' :
2997 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!");
2998 nPos++;
2999 Imp_SkipSpaces(aStr, nPos, nLen);
3001 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos))
3003 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3004 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3005 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3006 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3007 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen);
3008 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3009 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen);
3011 break;
3014 default:
3016 nPos++;
3017 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!");
3018 break;
3023 // #104076# end-process closed state of last poly
3024 if(mbIsClosed)
3026 if(pNotSoInnerSequence)
3028 // closed: add first point again
3029 sal_Int32 nX(pNotSoInnerSequence[0].X);
3030 sal_Int32 nY(pNotSoInnerSequence[0].Y);
3031 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL);
3035 // #87202# If it's a curve and it's closed the last point maybe too much
3036 // and just exported since SVG does not allow special handling of same
3037 // start and end point, remove this last point.
3038 // Evtl. correct the last curve flags, too.
3039 if(IsCurve() && IsClosed())
3041 // make one more loop over the PolyPolygon
3042 pOuterSequence = maPoly.getArray();
3043 pOuterFlags = maFlag.getArray();
3044 sal_Int32 nOuterCnt(maPoly.getLength());
3046 for(sal_Int32 a(0); a < nOuterCnt; a++)
3048 // get Polygon pointers
3049 awt::Point* pInnerSequence = pOuterSequence->getArray();
3050 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray();
3051 sal_Int32 nInnerCnt(pOuterSequence->getLength());
3053 while( nInnerCnt >= 2
3054 && ((pInnerSequence + (nInnerCnt - 2))->X == (pInnerSequence + (nInnerCnt - 1))->X)
3055 && ((pInnerSequence + (nInnerCnt - 2))->Y == (pInnerSequence + (nInnerCnt - 1))->Y)
3056 && drawing::PolygonFlags_CONTROL != *(pInnerFlags + (nInnerCnt - 2)))
3058 // remove last point from array
3059 pOuterSequence->realloc(nInnerCnt - 1);
3060 pOuterFlags->realloc(nInnerCnt - 1);
3062 // get new pointers
3063 pInnerSequence = pOuterSequence->getArray();
3064 pInnerFlags = pOuterFlags->getArray();
3065 nInnerCnt = pOuterSequence->getLength();
3068 // now evtl. correct the last curve flags
3069 if(nInnerCnt >= 4)
3071 if( pInnerSequence->X == (pInnerSequence + (nInnerCnt - 1))->X
3072 && pInnerSequence->Y == (pInnerSequence + (nInnerCnt - 1))->Y
3073 && drawing::PolygonFlags_CONTROL == *(pInnerFlags + 1)
3074 && drawing::PolygonFlags_CONTROL == *(pInnerFlags + (nInnerCnt - 2)))
3076 awt::Point aPrev = *(pInnerSequence + (nInnerCnt - 2));
3077 awt::Point aCurr = *pInnerSequence;
3078 awt::Point aNext = *(pInnerSequence + 1);
3079 ::basegfx::B2DVector aVec1(aPrev.X - aCurr.X, aPrev.Y - aCurr.Y);
3080 ::basegfx::B2DVector aVec2(aNext.X - aCurr.X, aNext.Y - aCurr.Y);
3081 bool bSameLength(false);
3082 bool bSameDirection(false);
3084 // get vector values
3085 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
3087 // set correct flag value
3088 if(bSameDirection)
3090 if(bSameLength)
3092 // set to PolygonFlags_SYMMETRIC
3093 *pInnerFlags = drawing::PolygonFlags_SYMMETRIC;
3094 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SYMMETRIC;
3096 else
3098 // set to PolygonFlags_SMOOTH
3099 *pInnerFlags = drawing::PolygonFlags_SMOOTH;
3100 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SMOOTH;
3103 else
3105 // set to PolygonFlags_NORMAL
3106 *pInnerFlags = drawing::PolygonFlags_NORMAL;
3107 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_NORMAL;
3112 // switch to next Polygon
3113 pOuterSequence++;
3114 pOuterFlags++;
3120 // eof