Bump for 4.0-11
[LibreOffice.git] / xmloff / source / draw / xexptran.cxx
blob215844461fe879425a9e84002ddc09cc738d8fe8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xexptran.hxx"
21 #include <tools/debug.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <sax/tools/converter.hxx>
24 #include <xmloff/xmluconv.hxx>
25 #include <xmloff/xmlexp.hxx>
26 #include <xmloff/xmlimp.hxx>
27 #include <tools/helpers.hxx>
28 #include <basegfx/vector/b2dvector.hxx>
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <basegfx/tuple/b3dtuple.hxx>
31 #include <basegfx/matrix/b3dhommatrix.hxx>
32 #include <basegfx/polygon/b2dpolypolygon.hxx>
33 #include <basegfx/polygon/b2dpolypolygontools.hxx>
34 #include <basegfx/tools/unotools.hxx>
36 using ::rtl::OUString;
37 using ::rtl::OUStringBuffer;
39 using namespace ::com::sun::star;
41 //////////////////////////////////////////////////////////////////////////////
42 // Defines
44 #define BORDER_INTEGERS_ARE_EQUAL (4)
46 //////////////////////////////////////////////////////////////////////////////
47 // Predeclarations
49 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen);
50 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection)
52 const sal_Int32 nLen1(FRound(aVec1.getLength()));
53 const sal_Int32 nLen2(FRound(aVec2.getLength()));
54 aVec1.normalize();
55 aVec2.normalize();
56 aVec1 += aVec2;
57 const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0)));
59 bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL);
60 bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL);
64 //////////////////////////////////////////////////////////////////////////////
65 //////////////////////////////////////////////////////////////////////////////
66 // parsing help functions for simple chars
67 void Imp_SkipSpaces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
69 while(rPos < nLen
70 && sal_Unicode(' ') == rStr[rPos])
71 rPos++;
74 void Imp_SkipSpacesAndOpeningBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
76 while(rPos < nLen
77 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode('(') == rStr[rPos]))
78 rPos++;
81 void Imp_SkipSpacesAndCommas(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
83 while(rPos < nLen
84 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(',') == rStr[rPos]))
85 rPos++;
88 void Imp_SkipSpacesAndClosingBraces(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
90 while(rPos < nLen
91 && (sal_Unicode(' ') == rStr[rPos] || sal_Unicode(')') == rStr[rPos]))
92 rPos++;
95 //////////////////////////////////////////////////////////////////////////////
96 //////////////////////////////////////////////////////////////////////////////
97 // parsing help functions for integer numbers
99 bool Imp_IsOnNumberChar(const OUString& rStr, const sal_Int32 nPos, bool bSignAllowed = true)
101 sal_Unicode aChar(rStr[nPos]);
103 if((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
104 || (bSignAllowed && sal_Unicode('+') == aChar)
105 || (bSignAllowed && sal_Unicode('-') == aChar)
107 return true;
108 return false;
111 bool Imp_IsOnUnitChar(const OUString& rStr, const sal_Int32 nPos)
113 sal_Unicode aChar(rStr[nPos]);
115 if((sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
116 || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
117 || sal_Unicode('%') == aChar
119 return true;
120 return false;
123 void Imp_SkipNumber(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen)
125 bool bSignAllowed(true);
127 while(rPos < nLen && Imp_IsOnNumberChar(rStr, rPos, bSignAllowed))
129 bSignAllowed = false;
130 rPos++;
134 void Imp_SkipNumberAndSpacesAndCommas(const OUString& rStr, sal_Int32& rPos,
135 const sal_Int32 nLen)
137 Imp_SkipNumber(rStr, rPos, nLen);
138 Imp_SkipSpacesAndCommas(rStr, rPos, nLen);
141 void Imp_PutNumberChar(OUString& rStr, sal_Int32 nValue)
143 OUStringBuffer sStringBuffer;
144 ::sax::Converter::convertNumber(sStringBuffer, nValue);
145 rStr += OUString(sStringBuffer.makeStringAndClear());
148 void Imp_PutNumberCharWithSpace(OUString& rStr, sal_Int32 nValue)
150 const sal_Int32 aLen(rStr.getLength());
151 if(aLen)
152 if(Imp_IsOnNumberChar(rStr, aLen - 1, false) && nValue >= 0)
153 rStr += rtl::OUString(static_cast<sal_Unicode>(' '));
154 Imp_PutNumberChar(rStr, nValue);
157 //////////////////////////////////////////////////////////////////////////////
158 //////////////////////////////////////////////////////////////////////////////
159 // parsing help functions for double numbers
161 void Imp_SkipDouble(const OUString& rStr, sal_Int32& rPos, const sal_Int32)
163 sal_Unicode aChar(rStr[rPos]);
165 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
166 aChar = rStr[++rPos];
168 while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
169 || sal_Unicode('.') == aChar)
171 aChar = rStr[++rPos];
174 if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
176 aChar = rStr[++rPos];
178 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
179 aChar = rStr[++rPos];
181 while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
183 aChar = rStr[++rPos];
188 double Imp_GetDoubleChar(const OUString& rStr, sal_Int32& rPos, const sal_Int32 nLen,
189 const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false)
191 sal_Unicode aChar(rStr[rPos]);
192 OUStringBuffer sNumberString;
194 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
196 sNumberString.append(rStr[rPos]);
197 aChar = rStr[++rPos];
200 while((sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
201 || sal_Unicode('.') == aChar)
203 sNumberString.append(rStr[rPos]);
204 aChar = rStr[++rPos];
207 if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
209 sNumberString.append(rStr[rPos]);
210 aChar = rStr[++rPos];
212 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
214 sNumberString.append(rStr[rPos]);
215 aChar = rStr[++rPos];
218 while(sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
220 sNumberString.append(rStr[rPos]);
221 aChar = rStr[++rPos];
225 if(bLookForUnits)
227 Imp_SkipSpaces(rStr, rPos, nLen);
228 while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos))
229 sNumberString.append(rStr[rPos++]);
232 if(sNumberString.getLength())
234 if(bLookForUnits)
235 rConv.convertDouble(fRetval, sNumberString.makeStringAndClear(), true);
236 else
238 ::sax::Converter::convertDouble(fRetval,
239 sNumberString.makeStringAndClear());
243 return fRetval;
246 void Imp_PutDoubleChar(OUString& rStr, const SvXMLUnitConverter& rConv, double fValue,
247 bool bConvertUnits = false)
249 OUStringBuffer sStringBuffer;
251 if(bConvertUnits)
252 rConv.convertDouble(sStringBuffer, fValue, true);
253 else
255 ::sax::Converter::convertDouble(sStringBuffer, fValue);
258 rStr += OUString(sStringBuffer.makeStringAndClear());
261 //////////////////////////////////////////////////////////////////////////////
262 //////////////////////////////////////////////////////////////////////////////
263 // base class of all 2D transform objects
265 struct ImpSdXMLExpTransObj2DBase
267 sal_uInt16 mnType;
268 ImpSdXMLExpTransObj2DBase(sal_uInt16 nType)
269 : mnType(nType) {}
272 //////////////////////////////////////////////////////////////////////////////
273 // possible object types for 2D
275 #define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000
276 #define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001
277 #define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002
278 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003
279 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004
280 #define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005
282 //////////////////////////////////////////////////////////////////////////////
283 // classes of objects, different sizes
285 struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase
287 double mfRotate;
288 ImpSdXMLExpTransObj2DRotate(double fVal)
289 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {}
291 struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase
293 ::basegfx::B2DTuple maScale;
294 ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew)
295 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {}
297 struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase
299 ::basegfx::B2DTuple maTranslate;
300 ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew)
301 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {}
303 struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase
305 double mfSkewX;
306 ImpSdXMLExpTransObj2DSkewX(double fVal)
307 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {}
309 struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase
311 double mfSkewY;
312 ImpSdXMLExpTransObj2DSkewY(double fVal)
313 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {}
315 struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase
317 ::basegfx::B2DHomMatrix maMatrix;
318 ImpSdXMLExpTransObj2DMatrix(const ::basegfx::B2DHomMatrix& rNew)
319 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(rNew) {}
322 //////////////////////////////////////////////////////////////////////////////
323 //////////////////////////////////////////////////////////////////////////////
324 // delete all entries in list
326 void SdXMLImExTransform2D::EmptyList()
328 const sal_uInt32 nCount = maList.size();
329 for(sal_uInt32 a(0L); a < nCount; a++)
331 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
333 switch(pObj->mnType)
335 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
337 delete (ImpSdXMLExpTransObj2DRotate*)pObj;
338 break;
340 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
342 delete (ImpSdXMLExpTransObj2DScale*)pObj;
343 break;
345 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
347 delete (ImpSdXMLExpTransObj2DTranslate*)pObj;
348 break;
350 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
352 delete (ImpSdXMLExpTransObj2DSkewX*)pObj;
353 break;
355 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
357 delete (ImpSdXMLExpTransObj2DSkewY*)pObj;
358 break;
360 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
362 delete (ImpSdXMLExpTransObj2DMatrix*)pObj;
363 break;
365 default :
367 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
368 break;
373 maList.clear();
376 //////////////////////////////////////////////////////////////////////////////
377 // add members
379 void SdXMLImExTransform2D::AddRotate(double fNew)
381 if(fNew != 0.0)
382 maList.push_back(new ImpSdXMLExpTransObj2DRotate(fNew));
385 void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew)
387 if(!rNew.equalZero())
388 maList.push_back(new ImpSdXMLExpTransObj2DTranslate(rNew));
391 void SdXMLImExTransform2D::AddSkewX(double fNew)
393 if(fNew != 0.0)
394 maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fNew));
397 //////////////////////////////////////////////////////////////////////////////
398 // gen string for export
399 const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv)
401 OUString aNewString;
402 OUString aClosingBrace(sal_Unicode(')'));
403 OUString aEmptySpace(sal_Unicode(' '));
405 const sal_uInt32 nCount = maList.size();
406 for(sal_uInt32 a(0L); a < nCount; a++)
408 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
409 switch(pObj->mnType)
411 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
413 aNewString += OUString( "rotate (" );
414 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate);
415 aNewString += aClosingBrace;
416 break;
418 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
420 aNewString += OUString( "scale (" );
421 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getX());
422 aNewString += aEmptySpace;
423 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale.getY());
424 aNewString += aClosingBrace;
425 break;
427 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
429 aNewString += OUString( "translate (" );
430 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getX(), true);
431 aNewString += aEmptySpace;
432 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate.getY(), true);
433 aNewString += aClosingBrace;
434 break;
436 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
438 aNewString += OUString( "skewX (" );
439 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX);
440 aNewString += aClosingBrace;
441 break;
443 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
445 aNewString += OUString( "skewY (" );
446 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY);
447 aNewString += aClosingBrace;
448 break;
450 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
452 aNewString += OUString( "matrix (" );
454 // a
455 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 0));
456 aNewString += aEmptySpace;
458 // b
459 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 0));
460 aNewString += aEmptySpace;
462 // c
463 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 1));
464 aNewString += aEmptySpace;
466 // d
467 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 1));
468 aNewString += aEmptySpace;
470 // e
471 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(0, 2), true);
472 aNewString += aEmptySpace;
474 // f
475 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix.get(1, 2), true);
477 aNewString += aClosingBrace;
478 break;
480 default :
482 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
483 break;
487 // if not the last entry, add one space to next tag
488 if(a + 1UL != maList.size())
490 aNewString += aEmptySpace;
494 // fill string form OUString
495 msString = aNewString;
497 return msString;
500 //////////////////////////////////////////////////////////////////////////////
501 // sets new string, parses it and generates entries
502 void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
504 msString = rNew;
505 EmptyList();
507 if(!msString.isEmpty())
509 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
510 const sal_Int32 nLen(aStr.getLength());
512 const OUString aString_rotate( "rotate" );
513 const OUString aString_scale( "scale" );
514 const OUString aString_translate( "translate" );
515 const OUString aString_skewX( "skewX" );
516 const OUString aString_skewY( "skewY" );
517 const OUString aString_matrix( "matrix" );
519 sal_Int32 nPos(0);
521 while(nPos < nLen)
523 // skip spaces
524 Imp_SkipSpaces(aStr, nPos, nLen);
526 // look for tag
527 if(nPos < nLen)
529 if(nPos == aStr.indexOf(aString_rotate, nPos))
531 double fValue(0.0);
532 nPos += 6;
533 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
534 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
535 if(fValue != 0.0)
536 maList.push_back(new ImpSdXMLExpTransObj2DRotate(fValue));
538 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
540 else if(nPos == aStr.indexOf(aString_scale, nPos))
542 ::basegfx::B2DTuple aValue(1.0, 1.0);
543 nPos += 5;
544 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
545 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
546 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
547 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
549 if(aValue.getX() != 1.0 || aValue.getY() != 1.0)
550 maList.push_back(new ImpSdXMLExpTransObj2DScale(aValue));
552 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
554 else if(nPos == aStr.indexOf(aString_translate, nPos))
556 ::basegfx::B2DTuple aValue;
557 nPos += 9;
558 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
559 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
560 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
561 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
563 if(!aValue.equalZero())
564 maList.push_back(new ImpSdXMLExpTransObj2DTranslate(aValue));
566 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
568 else if(nPos == aStr.indexOf(aString_skewX, nPos))
570 double fValue(0.0);
571 nPos += 5;
572 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
573 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
574 if(fValue != 0.0)
575 maList.push_back(new ImpSdXMLExpTransObj2DSkewX(fValue));
577 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
579 else if(nPos == aStr.indexOf(aString_skewY, nPos))
581 double fValue(0.0);
582 nPos += 5;
583 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
584 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
585 if(fValue != 0.0)
586 maList.push_back(new ImpSdXMLExpTransObj2DSkewY(fValue));
588 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
590 else if(nPos == aStr.indexOf(aString_matrix, nPos))
592 ::basegfx::B2DHomMatrix aValue;
594 nPos += 6;
595 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
597 // a
598 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
599 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
601 // b
602 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
603 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
605 // c
606 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
607 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
609 // d
610 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
611 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
613 // e
614 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true));
615 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
617 // f
618 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true));
619 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
621 if(!aValue.isIdentity())
622 maList.push_back(new ImpSdXMLExpTransObj2DMatrix(aValue));
624 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
626 else
628 nPos++;
635 void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans)
637 rFullTrans.identity();
639 const sal_uInt32 nCount = maList.size();
640 for(sal_uInt32 a(0L); a < nCount; a++)
642 ImpSdXMLExpTransObj2DBase* pObj = maList[a];
643 switch(pObj->mnType)
645 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
647 // #i78696#
648 // mfRotate is mathematically wrong oriented since we export/import the angle
649 // values mirrored. This error is fixed in the API, but not yet in the FileFormat.
650 // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next
651 // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary
652 // to mirror the value here
653 rFullTrans.rotate(((ImpSdXMLExpTransObj2DRotate*)pObj)->mfRotate * -1.0);
654 break;
656 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
658 const ::basegfx::B2DTuple& rScale = ((ImpSdXMLExpTransObj2DScale*)pObj)->maScale;
659 rFullTrans.scale(rScale.getX(), rScale.getY());
660 break;
662 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
664 const ::basegfx::B2DTuple& rTranslate = ((ImpSdXMLExpTransObj2DTranslate*)pObj)->maTranslate;
665 rFullTrans.translate(rTranslate.getX(), rTranslate.getY());
666 break;
668 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
670 rFullTrans.shearX(tan(((ImpSdXMLExpTransObj2DSkewX*)pObj)->mfSkewX));
671 break;
673 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
675 rFullTrans.shearY(tan(((ImpSdXMLExpTransObj2DSkewY*)pObj)->mfSkewY));
676 break;
678 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
680 rFullTrans *= ((ImpSdXMLExpTransObj2DMatrix*)pObj)->maMatrix;
681 break;
683 default :
685 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
686 break;
692 //////////////////////////////////////////////////////////////////////////////
693 //////////////////////////////////////////////////////////////////////////////
694 // base class of all 3D transform objects
696 struct ImpSdXMLExpTransObj3DBase
698 sal_uInt16 mnType;
699 ImpSdXMLExpTransObj3DBase(sal_uInt16 nType)
700 : mnType(nType) {}
703 //////////////////////////////////////////////////////////////////////////////
704 // possible object types for 3D
706 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000
707 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001
708 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002
709 #define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003
710 #define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004
711 #define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005
713 //////////////////////////////////////////////////////////////////////////////
714 // classes of objects, different sizes
716 struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase
718 double mfRotateX;
719 ImpSdXMLExpTransObj3DRotateX(double fVal)
720 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {}
722 struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase
724 double mfRotateY;
725 ImpSdXMLExpTransObj3DRotateY(double fVal)
726 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {}
728 struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase
730 double mfRotateZ;
731 ImpSdXMLExpTransObj3DRotateZ(double fVal)
732 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {}
734 struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase
736 ::basegfx::B3DTuple maScale;
737 ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew)
738 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {}
740 struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase
742 ::basegfx::B3DTuple maTranslate;
743 ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew)
744 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {}
746 struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase
748 ::basegfx::B3DHomMatrix maMatrix;
749 ImpSdXMLExpTransObj3DMatrix(const ::basegfx::B3DHomMatrix& rNew)
750 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(rNew) {}
753 //////////////////////////////////////////////////////////////////////////////
754 //////////////////////////////////////////////////////////////////////////////
755 // delete all entries in list
757 void SdXMLImExTransform3D::EmptyList()
759 const sal_uInt32 nCount = maList.size();
760 for(sal_uInt32 a(0L); a < nCount; a++)
762 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
764 switch(pObj->mnType)
766 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
768 delete (ImpSdXMLExpTransObj3DRotateX*)pObj;
769 break;
771 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
773 delete (ImpSdXMLExpTransObj3DRotateY*)pObj;
774 break;
776 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
778 delete (ImpSdXMLExpTransObj3DRotateZ*)pObj;
779 break;
781 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
783 delete (ImpSdXMLExpTransObj3DScale*)pObj;
784 break;
786 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
788 delete (ImpSdXMLExpTransObj3DTranslate*)pObj;
789 break;
791 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
793 delete (ImpSdXMLExpTransObj3DMatrix*)pObj;
794 break;
796 default :
798 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
799 break;
804 maList.clear();
807 //////////////////////////////////////////////////////////////////////////////
808 // add members
810 void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew)
812 if(!rNew.isIdentity())
813 maList.push_back(new ImpSdXMLExpTransObj3DMatrix(rNew));
816 void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat)
818 ::basegfx::B3DHomMatrix aExportMatrix;
820 aExportMatrix.set(0, 0, xHomMat.Line1.Column1);
821 aExportMatrix.set(0, 1, xHomMat.Line1.Column2);
822 aExportMatrix.set(0, 2, xHomMat.Line1.Column3);
823 aExportMatrix.set(0, 3, xHomMat.Line1.Column4);
824 aExportMatrix.set(1, 0, xHomMat.Line2.Column1);
825 aExportMatrix.set(1, 1, xHomMat.Line2.Column2);
826 aExportMatrix.set(1, 2, xHomMat.Line2.Column3);
827 aExportMatrix.set(1, 3, xHomMat.Line2.Column4);
828 aExportMatrix.set(2, 0, xHomMat.Line3.Column1);
829 aExportMatrix.set(2, 1, xHomMat.Line3.Column2);
830 aExportMatrix.set(2, 2, xHomMat.Line3.Column3);
831 aExportMatrix.set(2, 3, xHomMat.Line3.Column4);
833 AddMatrix(aExportMatrix);
836 //////////////////////////////////////////////////////////////////////////////
837 // gen string for export
838 const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv)
840 OUString aNewString;
841 OUString aClosingBrace(sal_Unicode(')'));
842 OUString aEmptySpace(sal_Unicode(' '));
844 const sal_uInt32 nCount = maList.size();
845 for(sal_uInt32 a(0L); a < nCount; a++)
847 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
848 switch(pObj->mnType)
850 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
852 aNewString += OUString( "rotatex (" );
853 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX);
854 aNewString += aClosingBrace;
855 break;
857 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
859 aNewString += OUString( "rotatey (" );
860 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY);
861 aNewString += aClosingBrace;
862 break;
864 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
866 aNewString += OUString( "rotatez (" );
867 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
868 aNewString += aClosingBrace;
869 break;
871 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
873 aNewString += OUString( "scale (" );
874 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getX());
875 aNewString += aEmptySpace;
876 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getY());
877 aNewString += aEmptySpace;
878 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale.getZ());
879 aNewString += aClosingBrace;
880 break;
882 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
884 aNewString += OUString( "translate (" );
885 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getX(), true);
886 aNewString += aEmptySpace;
887 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getY(), true);
888 aNewString += aEmptySpace;
889 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate.getZ(), true);
890 aNewString += aClosingBrace;
891 break;
893 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
895 aNewString += OUString( "matrix (" );
897 // a
898 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 0));
899 aNewString += aEmptySpace;
901 // b
902 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 0));
903 aNewString += aEmptySpace;
905 // c
906 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 0));
907 aNewString += aEmptySpace;
909 // d
910 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 1));
911 aNewString += aEmptySpace;
913 // e
914 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 1));
915 aNewString += aEmptySpace;
917 // f
918 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 1));
919 aNewString += aEmptySpace;
921 // g
922 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 2));
923 aNewString += aEmptySpace;
925 // h
926 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 2));
927 aNewString += aEmptySpace;
929 // i
930 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 2));
931 aNewString += aEmptySpace;
933 // j
934 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(0, 3), true);
935 aNewString += aEmptySpace;
937 // k
938 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(1, 3), true);
939 aNewString += aEmptySpace;
941 // l
942 Imp_PutDoubleChar(aNewString, rConv, ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix.get(2, 3), true);
944 aNewString += aClosingBrace;
945 break;
947 default :
949 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
950 break;
954 // if not the last entry, add one space to next tag
955 if(a + 1UL != maList.size())
957 aNewString += aEmptySpace;
961 // fill string form OUString
962 msString = aNewString;
964 return msString;
967 //////////////////////////////////////////////////////////////////////////////
968 // for Import: constructor with string, parses it and generates entries
969 SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv)
971 SetString(rNew, rConv);
974 //////////////////////////////////////////////////////////////////////////////
975 // sets new string, parses it and generates entries
976 void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
978 msString = rNew;
979 EmptyList();
981 if(!msString.isEmpty())
983 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
984 const sal_Int32 nLen(aStr.getLength());
986 const OUString aString_rotatex( "rotatex" );
987 const OUString aString_rotatey( "rotatey" );
988 const OUString aString_rotatez( "rotatez" );
989 const OUString aString_scale( "scale" );
990 const OUString aString_translate( "translate" );
991 const OUString aString_matrix( "matrix" );
993 sal_Int32 nPos(0);
995 while(nPos < nLen)
997 // skip spaces
998 Imp_SkipSpaces(aStr, nPos, nLen);
1000 // look for tag
1001 if(nPos < nLen)
1003 if(nPos == aStr.indexOf(aString_rotatex, nPos))
1005 double fValue(0.0);
1007 nPos += 7;
1008 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1009 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1010 if(fValue != 0.0)
1011 maList.push_back(new ImpSdXMLExpTransObj3DRotateX(fValue));
1013 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1015 else if(nPos == aStr.indexOf(aString_rotatey, nPos))
1017 double fValue(0.0);
1019 nPos += 7;
1020 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1021 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1022 if(fValue != 0.0)
1023 maList.push_back(new ImpSdXMLExpTransObj3DRotateY(fValue));
1025 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1027 else if(nPos == aStr.indexOf(aString_rotatez, nPos))
1029 double fValue(0.0);
1031 nPos += 7;
1032 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1033 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
1034 if(fValue != 0.0)
1035 maList.push_back(new ImpSdXMLExpTransObj3DRotateZ(fValue));
1037 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1039 else if(nPos == aStr.indexOf(aString_scale, nPos))
1041 ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0);
1043 nPos += 5;
1044 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1045 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
1046 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1047 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
1048 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1049 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ()));
1051 if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ())
1052 maList.push_back(new ImpSdXMLExpTransObj3DScale(aValue));
1054 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1056 else if(nPos == aStr.indexOf(aString_translate, nPos))
1058 ::basegfx::B3DTuple aValue;
1060 nPos += 9;
1061 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1062 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
1063 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1064 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
1065 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1066 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true));
1068 if(!aValue.equalZero())
1069 maList.push_back(new ImpSdXMLExpTransObj3DTranslate(aValue));
1071 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1073 else if(nPos == aStr.indexOf(aString_matrix, nPos))
1075 ::basegfx::B3DHomMatrix aValue;
1077 nPos += 6;
1078 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
1080 // a
1081 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
1082 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1084 // b
1085 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
1086 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1088 // c
1089 aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0)));
1090 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1092 // d
1093 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
1094 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1096 // e
1097 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
1098 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1100 // f
1101 aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1)));
1102 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1104 // g
1105 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2)));
1106 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1108 // h
1109 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2)));
1110 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1112 // i
1113 aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2)));
1114 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1116 // j
1117 aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true));
1118 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1120 // k
1121 aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true));
1122 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1124 // l
1125 aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true));
1126 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1128 if(!aValue.isIdentity())
1129 maList.push_back(new ImpSdXMLExpTransObj3DMatrix(aValue));
1131 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
1133 else
1135 nPos++;
1142 bool SdXMLImExTransform3D::GetFullHomogenTransform(com::sun::star::drawing::HomogenMatrix& xHomMat)
1144 ::basegfx::B3DHomMatrix aFullTransform;
1145 GetFullTransform(aFullTransform);
1147 if(!aFullTransform.isIdentity())
1149 xHomMat.Line1.Column1 = aFullTransform.get(0, 0);
1150 xHomMat.Line1.Column2 = aFullTransform.get(0, 1);
1151 xHomMat.Line1.Column3 = aFullTransform.get(0, 2);
1152 xHomMat.Line1.Column4 = aFullTransform.get(0, 3);
1154 xHomMat.Line2.Column1 = aFullTransform.get(1, 0);
1155 xHomMat.Line2.Column2 = aFullTransform.get(1, 1);
1156 xHomMat.Line2.Column3 = aFullTransform.get(1, 2);
1157 xHomMat.Line2.Column4 = aFullTransform.get(1, 3);
1159 xHomMat.Line3.Column1 = aFullTransform.get(2, 0);
1160 xHomMat.Line3.Column2 = aFullTransform.get(2, 1);
1161 xHomMat.Line3.Column3 = aFullTransform.get(2, 2);
1162 xHomMat.Line3.Column4 = aFullTransform.get(2, 3);
1164 xHomMat.Line4.Column1 = aFullTransform.get(3, 0);
1165 xHomMat.Line4.Column2 = aFullTransform.get(3, 1);
1166 xHomMat.Line4.Column3 = aFullTransform.get(3, 2);
1167 xHomMat.Line4.Column4 = aFullTransform.get(3, 3);
1169 return true;
1172 return false;
1175 void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans)
1177 rFullTrans.identity();
1179 const sal_uInt32 nCount = maList.size();
1180 for(sal_uInt32 a(0L); a < nCount; a++)
1182 ImpSdXMLExpTransObj3DBase* pObj = maList[a];
1183 switch(pObj->mnType)
1185 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
1187 rFullTrans.rotate(((ImpSdXMLExpTransObj3DRotateX*)pObj)->mfRotateX, 0.0, 0.0);
1188 break;
1190 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
1192 rFullTrans.rotate(0.0, ((ImpSdXMLExpTransObj3DRotateY*)pObj)->mfRotateY, 0.0);
1193 break;
1195 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
1197 rFullTrans.rotate(0.0, 0.0, ((ImpSdXMLExpTransObj3DRotateZ*)pObj)->mfRotateZ);
1198 break;
1200 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
1202 const ::basegfx::B3DTuple& rScale = ((ImpSdXMLExpTransObj3DScale*)pObj)->maScale;
1203 rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ());
1204 break;
1206 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
1208 const ::basegfx::B3DTuple& rTranslate = ((ImpSdXMLExpTransObj3DTranslate*)pObj)->maTranslate;
1209 rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
1210 break;
1212 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
1214 rFullTrans *= ((ImpSdXMLExpTransObj3DMatrix*)pObj)->maMatrix;
1215 break;
1217 default :
1219 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
1220 break;
1226 //////////////////////////////////////////////////////////////////////////////
1227 //////////////////////////////////////////////////////////////////////////////
1229 SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX, sal_Int32 nY, sal_Int32 nW, sal_Int32 nH)
1230 : mnX( nX ),
1231 mnY( nY ),
1232 mnW( nW ),
1233 mnH( nH )
1237 // #100617# Asked vincent hardy: svg:viewBox values may be double precision.
1238 SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv)
1239 : msString(rNew),
1240 mnX( 0L ),
1241 mnY( 0L ),
1242 mnW( 1000L ),
1243 mnH( 1000L )
1245 if(!msString.isEmpty())
1247 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1248 const sal_Int32 nLen(aStr.getLength());
1249 sal_Int32 nPos(0);
1251 // skip starting spaces
1252 Imp_SkipSpaces(aStr, nPos, nLen);
1254 // get mX, #100617# be prepared for doubles
1255 mnX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnX));
1257 // skip spaces and commas
1258 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1260 // get mY, #100617# be prepared for doubles
1261 mnY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnY));
1263 // skip spaces and commas
1264 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1266 // get mW, #100617# be prepared for doubles
1267 mnW = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnW));
1269 // skip spaces and commas
1270 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1272 // get mH, #100617# be prepared for doubles
1273 mnH = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)mnH));
1277 const OUString& SdXMLImExViewBox::GetExportString()
1279 OUString aNewString;
1280 OUString aEmptySpace(sal_Unicode(' '));
1282 Imp_PutNumberChar(aNewString, mnX);
1283 aNewString += aEmptySpace;
1285 Imp_PutNumberChar(aNewString, mnY);
1286 aNewString += aEmptySpace;
1288 Imp_PutNumberChar(aNewString, mnW);
1289 aNewString += aEmptySpace;
1291 Imp_PutNumberChar(aNewString, mnH);
1293 // set new string
1294 msString = aNewString;
1296 return msString;
1299 //////////////////////////////////////////////////////////////////////////////
1300 //////////////////////////////////////////////////////////////////////////////
1302 SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence* pPoints,
1303 const SdXMLImExViewBox& rViewBox,
1304 const awt::Point& rObjectPos,
1305 const awt::Size& rObjectSize,
1306 // #96328#
1307 const bool bClosed)
1308 : maPoly( 0L )
1310 DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExPointsElement(!)");
1312 // add polygon to string
1313 sal_Int32 nCnt(pPoints->getLength());
1315 // #104076# Convert to string only when at last one point included
1316 if(nCnt > 0)
1318 OUString aNewString;
1319 awt::Point* pArray = pPoints->getArray();
1321 // last point same? Ignore it.
1322 // #96328# ...but only when polygon is CLOSED
1323 if(bClosed && (pArray->X == (pArray + (nCnt - 1))->X) && (pArray->Y == (pArray + (nCnt - 1))->Y))
1324 nCnt--;
1326 // object size and ViewBox size different?
1327 bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1328 || rObjectSize.Height != rViewBox.GetHeight());
1329 bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1331 for(sal_Int32 a(0L); a < nCnt; a++)
1333 // prepare coordinates
1334 sal_Int32 nX( pArray->X - rObjectPos.X );
1335 sal_Int32 nY( pArray->Y - rObjectPos.Y );
1337 if(bScale && rObjectSize.Width && rObjectSize.Height)
1339 nX = (nX * rViewBox.GetWidth()) / rObjectSize.Width;
1340 nY = (nY * rViewBox.GetHeight()) / rObjectSize.Height;
1343 if(bTranslate)
1345 nX += rViewBox.GetX();
1346 nY += rViewBox.GetY();
1349 // X and comma
1350 Imp_PutNumberChar(aNewString, nX);
1351 aNewString += rtl::OUString(static_cast<sal_Unicode>(','));
1353 // Y and space (not for last)
1354 Imp_PutNumberChar(aNewString, nY);
1355 if(a + 1 != nCnt)
1356 aNewString += rtl::OUString(static_cast<sal_Unicode>(' '));
1358 // next point
1359 pArray++;
1362 // set new string
1363 msString = aNewString;
1367 // #100617# svg:polyline or svg:polygon values may be double precision.
1368 SdXMLImExPointsElement::SdXMLImExPointsElement(const OUString& rNew,
1369 const SdXMLImExViewBox& rViewBox,
1370 const awt::Point& rObjectPos,
1371 const awt::Size& rObjectSize,
1372 const SvXMLUnitConverter& rConv)
1373 : msString( rNew ),
1374 maPoly( 0L )
1376 // convert string to polygon
1377 const OUString aStr(msString.getStr(), (sal_uInt16)msString.getLength());
1378 const sal_Int32 nLen(aStr.getLength());
1379 sal_Int32 nPos(0);
1380 sal_Int32 nNumPoints(0L);
1382 // skip starting spaces
1383 Imp_SkipSpaces(aStr, nPos, nLen);
1385 // count points in first loop
1386 while(nPos < nLen)
1388 // skip number, #100617# be prepared for doubles
1389 Imp_SkipDouble(aStr, nPos, nLen);
1391 // skip spaces and commas
1392 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1394 // skip number, #100617# be prepared for doubles
1395 Imp_SkipDouble(aStr, nPos, nLen);
1397 // skip spaces and commas
1398 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1400 // one more point
1401 nNumPoints++;
1404 // second loop
1405 if(nNumPoints)
1407 nPos = 0;
1408 maPoly.realloc(1);
1409 drawing::PointSequence* pOuterSequence = maPoly.getArray();
1410 pOuterSequence->realloc(nNumPoints);
1411 awt::Point* pInnerSequence = pOuterSequence->getArray();
1413 // object size and ViewBox size different?
1414 bool bScale(rObjectSize.Width != rViewBox.GetWidth()
1415 || rObjectSize.Height != rViewBox.GetHeight());
1416 bool bTranslate(rViewBox.GetX() != 0L || rViewBox.GetY() != 0L);
1418 // skip starting spaces
1419 Imp_SkipSpaces(aStr, nPos, nLen);
1421 while(nPos < nLen)
1423 // prepare new parameter pair
1424 sal_Int32 nX(0L);
1425 sal_Int32 nY(0L);
1427 // get mX, #100617# be prepared for doubles
1428 nX = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nX));
1430 // skip spaces and commas
1431 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1433 // get mY, #100617# be prepared for doubles
1434 nY = FRound(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, (double)nY));
1436 // skip spaces and commas
1437 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1439 // prepare parameters
1440 if(bTranslate)
1442 nX -= rViewBox.GetX();
1443 nY -= rViewBox.GetY();
1446 if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight() )
1448 nX = (nX * rObjectSize.Width) / rViewBox.GetWidth();
1449 nY = (nY * rObjectSize.Height) / rViewBox.GetHeight();
1452 nX += rObjectPos.X;
1453 nY += rObjectPos.Y;
1455 // add new point
1456 *pInnerSequence = awt::Point( nX, nY );
1457 pInnerSequence++;
1462 //////////////////////////////////////////////////////////////////////////////
1463 //////////////////////////////////////////////////////////////////////////////
1465 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox& rViewBox,
1466 const SvXMLExport& rExport)
1467 : mrViewBox( rViewBox ),
1468 mbIsClosed( false ),
1469 mbIsCurve( false ),
1470 // fdo#47406 - handle writing svg:d path slightly different for
1471 // old odf versions and ODF1.2 compat mode - since ~all the legacy
1472 // ODF ecosystem interprets relative svg:d paths incorrectly,
1473 // write out absolute paths in those cases.
1474 mbRelative( rExport.getDefaultVersion() >= SvtSaveOptions::ODFVER_012 &&
1475 rExport.getDefaultVersion() != SvtSaveOptions::ODFVER_012_EXT_COMPAT ),
1476 mnLastX( 0L ),
1477 mnLastY( 0L ),
1478 maPoly()
1482 void Imp_GetPrevPos(awt::Point*& pPrevPos1,
1483 drawing::PolygonFlags& aPrevFlag1,
1484 const bool bClosed, awt::Point* pPoints,
1485 drawing::PolygonFlags* pFlags, const sal_Int32 nPos,
1486 const sal_Int32 nCnt, const sal_Int32 nAdd)
1488 if(bClosed)
1490 pPrevPos1 = pPoints + ((nPos + nCnt - nAdd) % nCnt);
1491 aPrevFlag1 = *(pFlags + ((nPos + nCnt - nAdd) % nCnt));
1493 else if(nPos > (nAdd - 1))
1495 pPrevPos1 = pPoints + (nPos - nAdd);
1496 aPrevFlag1 = *(pFlags + (nPos - nAdd));
1498 else
1499 pPrevPos1 = 0L;
1502 void Imp_PrepareCoorExport(sal_Int32& nX, sal_Int32& nY,
1503 const awt::Point* pPointArray, const awt::Point& rObjectPos,
1504 const awt::Size& rObjectSize, const SdXMLImExViewBox& mrViewBox,
1505 const bool bScale, const bool bTranslate)
1507 nX = pPointArray->X - rObjectPos.X;
1508 nY = pPointArray->Y - rObjectPos.Y;
1510 if(bScale && rObjectSize.Width && rObjectSize.Height )
1512 nX = (nX * mrViewBox.GetWidth()) / rObjectSize.Width;
1513 nY = (nY * mrViewBox.GetHeight()) / rObjectSize.Height;
1516 if(bTranslate)
1518 nX += mrViewBox.GetX();
1519 nY += mrViewBox.GetY();
1523 //#define TEST_QUADRATIC_CURVES
1524 #ifdef TEST_QUADRATIC_CURVES
1525 // To be able to test quadratic curve code: The code concerning to
1526 // bDoTestHere can be used (see below). Construct shapes which have their control
1527 // points on equal coordinates. When these are written, they can be
1528 // forced to create correct 'Q' and 'T' statements using this flag.
1529 // These may then be tested for import/exporting.
1530 static bool bDoTestHere(true);
1531 #endif // TEST_QUADRATIC_CURVES
1533 void SdXMLImExSvgDElement::AddPolygon(
1534 drawing::PointSequence* pPoints,
1535 drawing::FlagSequence* pFlags,
1536 const awt::Point& rObjectPos,
1537 const awt::Size& rObjectSize,
1538 bool bClosed)
1540 // Leaving the export stuff for the while, should eventually also
1541 // consolidated with basegfx svg support
1542 DBG_ASSERT(pPoints, "Empty PointSequence handed over to SdXMLImExSvgDElement(!)");
1544 sal_Int32 nCnt(pPoints->getLength());
1546 // #104076# Convert to string only when at last one point included
1547 if(nCnt > 0)
1549 // append polygon to string
1550 OUString aNewString;
1551 sal_Unicode aLastCommand = ' ';
1552 awt::Point* pPointArray = pPoints->getArray();
1554 // are the flags used at all? If not forget about them
1555 if(pFlags)
1557 sal_Int32 nFlagCnt(pFlags->getLength());
1559 if(nFlagCnt)
1561 bool bFlagsUsed(false);
1562 drawing::PolygonFlags* pFlagArray = pFlags->getArray();
1564 for(sal_Int32 a(0); !bFlagsUsed && a < nFlagCnt; a++)
1565 if(drawing::PolygonFlags_NORMAL != *pFlagArray++)
1566 bFlagsUsed = true;
1568 if(!bFlagsUsed)
1569 pFlags = 0L;
1571 else
1573 pFlags = 0L;
1577 // object size and ViewBox size different?
1578 bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
1579 || rObjectSize.Height != mrViewBox.GetHeight());
1580 bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
1582 // #87202# rework of point reduction:
1583 // Test for Last point same -> closed, ignore last point. Take
1584 // some more circumstances in account when looking at curve segments.
1585 drawing::PolygonFlags* pFlagArray = (pFlags) ? pFlags->getArray() : 0L;
1586 if((pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y))
1588 if(pFlags)
1590 // point needs to be ignored if point before it is
1591 // NO control point. Else the last point is needed
1592 // for exporting the last segment of the curve. That means
1593 // that the last and the first point will be saved double,
1594 // but SVG does not support a better solution here.
1595 if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2)))
1597 nCnt--;
1600 else
1602 // no curve, ignore last point
1603 nCnt--;
1607 // bezier poly, handle curves
1608 bool bDidWriteStart(false);
1609 sal_Int32 nStartX(0), nStartY(0);
1611 for(sal_Int32 a(0L); a < nCnt; a++)
1613 if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray)
1615 bool bDidWriteAsCurve(false);
1617 if(bDidWriteStart)
1619 if(pFlags)
1621 // real curve point, get previous to see if it's a control point
1622 awt::Point* pPrevPos1;
1623 drawing::PolygonFlags aPrevFlag1;
1625 Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(),
1626 pFlags->getArray(), a, nCnt, 1);
1628 if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1)
1630 // get previous2 to see if it's a control point, too
1631 awt::Point* pPrevPos2;
1632 drawing::PolygonFlags aPrevFlag2;
1634 Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(),
1635 pFlags->getArray(), a, nCnt, 2);
1637 if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2)
1639 // get previous3 to see if it's a curve point and if,
1640 // if it is fully symmetric or not
1641 awt::Point* pPrevPos3;
1642 drawing::PolygonFlags aPrevFlag3;
1644 Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(),
1645 pFlags->getArray(), a, nCnt, 3);
1647 if(pPrevPos3)
1649 // prepare coordinates
1650 sal_Int32 nX, nY;
1652 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
1653 mrViewBox, bScale, bTranslate);
1655 // #100617# test if this curve segment may be written as
1656 // a quadratic bezier
1657 // That's the case if both control points are in the same place
1658 // when they are prolonged to the common quadratic control point
1659 // Left: P = (3P1 - P0) / 2
1660 // Right: P = (3P2 - P3) / 2
1661 bool bIsQuadratic(false);
1662 const bool bEnableSaveQuadratic(false);
1664 sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0));
1665 sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0));
1666 sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0));
1667 sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0));
1668 sal_Int32 nDist(0);
1670 if(nPX_L != nPX_R)
1672 nDist += abs(nPX_L - nPX_R);
1675 if(nPY_L != nPY_R)
1677 nDist += abs(nPY_L - nPY_R);
1680 if(nDist <= BORDER_INTEGERS_ARE_EQUAL)
1682 if(bEnableSaveQuadratic)
1684 bIsQuadratic = true;
1688 #ifdef TEST_QUADRATIC_CURVES
1689 if(bDoTestHere)
1691 bIsQuadratic = false;
1693 if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y)
1694 bIsQuadratic = true;
1696 #endif // TEST_QUADRATIC_CURVES
1698 if(bIsQuadratic)
1700 #ifdef TEST_QUADRATIC_CURVES
1701 if(bDoTestHere)
1703 bool bPrevPointIsSymmetric(false);
1705 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1707 // get previous4 to see if it's a control point
1708 awt::Point* pPrevPos4;
1709 drawing::PolygonFlags aPrevFlag4;
1711 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1712 pFlags->getArray(), a, nCnt, 4);
1714 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1716 // okay, prevPos3 is symmetric (c2) and prevPos4
1717 // is existing control point, the 's' statement can be used
1718 bPrevPointIsSymmetric = true;
1722 if(bPrevPointIsSymmetric)
1724 // write a shorthand/smooth quadratic curveto entry (T)
1725 if(mbRelative)
1727 if(aLastCommand != sal_Unicode('t'))
1728 aNewString += OUString(sal_Unicode('t'));
1730 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1731 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1733 aLastCommand = sal_Unicode('t');
1735 else
1737 if(aLastCommand != sal_Unicode('T'))
1738 aNewString += OUString(sal_Unicode('T'));
1740 Imp_PutNumberCharWithSpace(aNewString, nX);
1741 Imp_PutNumberCharWithSpace(aNewString, nY);
1743 aLastCommand = sal_Unicode('T');
1746 else
1748 // prepare coordinates
1749 sal_Int32 nX1, nY1;
1751 Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize,
1752 mrViewBox, bScale, bTranslate);
1754 // write a quadratic curveto entry (Q)
1755 if(mbRelative)
1757 if(aLastCommand != sal_Unicode('q'))
1758 aNewString += OUString(sal_Unicode('q'));
1760 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1761 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1762 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1763 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1765 aLastCommand = sal_Unicode('q');
1767 else
1769 if(aLastCommand != sal_Unicode('Q'))
1770 aNewString += OUString(sal_Unicode('Q'));
1772 Imp_PutNumberCharWithSpace(aNewString, nX1);
1773 Imp_PutNumberCharWithSpace(aNewString, nY1);
1774 Imp_PutNumberCharWithSpace(aNewString, nX);
1775 Imp_PutNumberCharWithSpace(aNewString, nY);
1777 aLastCommand = sal_Unicode('Q');
1781 else
1783 #endif // TEST_QUADRATIC_CURVES
1784 awt::Point aNewPoint(nPX_L, nPY_L);
1785 bool bPrevPointIsSmooth(false);
1787 if(drawing::PolygonFlags_SMOOTH == aPrevFlag3)
1789 // get previous4 to see if it's a control point
1790 awt::Point* pPrevPos4;
1791 drawing::PolygonFlags aPrevFlag4;
1793 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1794 pFlags->getArray(), a, nCnt, 4);
1796 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1798 // okay, prevPos3 is smooth (c1) and prevPos4
1799 // is existing control point. Test if it's even symmetric
1800 // and thus the 'T' statement may be used.
1801 ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y);
1802 ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y);
1803 bool bSameLength(false);
1804 bool bSameDirection(false);
1806 // get vector values
1807 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection);
1809 if(bSameLength && bSameDirection)
1810 bPrevPointIsSmooth = true;
1814 if(bPrevPointIsSmooth)
1816 // write a shorthand/smooth quadratic curveto entry (T)
1817 if(mbRelative)
1819 if(aLastCommand != sal_Unicode('t'))
1820 aNewString += rtl::OUString(static_cast<sal_Unicode>('t'));
1822 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1823 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1825 aLastCommand = sal_Unicode('t');
1827 else
1829 if(aLastCommand != sal_Unicode('T'))
1830 aNewString += rtl::OUString(static_cast<sal_Unicode>('T'));
1832 Imp_PutNumberCharWithSpace(aNewString, nX);
1833 Imp_PutNumberCharWithSpace(aNewString, nY);
1835 aLastCommand = sal_Unicode('T');
1838 else
1840 // prepare coordinates
1841 sal_Int32 nX1, nY1;
1843 Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize,
1844 mrViewBox, bScale, bTranslate);
1846 // write a quadratic curveto entry (Q)
1847 if(mbRelative)
1849 if(aLastCommand != sal_Unicode('q'))
1850 aNewString += rtl::OUString(static_cast<sal_Unicode>('q'));
1852 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1853 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1854 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1855 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1857 aLastCommand = sal_Unicode('q');
1859 else
1861 if(aLastCommand != sal_Unicode('Q'))
1862 aNewString += rtl::OUString(static_cast<sal_Unicode>('Q'));
1864 Imp_PutNumberCharWithSpace(aNewString, nX1);
1865 Imp_PutNumberCharWithSpace(aNewString, nY1);
1866 Imp_PutNumberCharWithSpace(aNewString, nX);
1867 Imp_PutNumberCharWithSpace(aNewString, nY);
1869 aLastCommand = sal_Unicode('Q');
1872 #ifdef TEST_QUADRATIC_CURVES
1874 #endif // TEST_QUADRATIC_CURVES
1876 else
1878 bool bPrevPointIsSymmetric(false);
1880 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3)
1882 // get previous4 to see if it's a control point
1883 awt::Point* pPrevPos4;
1884 drawing::PolygonFlags aPrevFlag4;
1886 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(),
1887 pFlags->getArray(), a, nCnt, 4);
1889 if(drawing::PolygonFlags_CONTROL == aPrevFlag4)
1891 // okay, prevPos3 is symmetric (c2) and prevPos4
1892 // is existing control point, the 's' statement can be used
1893 bPrevPointIsSymmetric = true;
1897 // prepare coordinates
1898 sal_Int32 nX2, nY2;
1900 Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize,
1901 mrViewBox, bScale, bTranslate);
1903 if(bPrevPointIsSymmetric)
1905 // write a shorthand/smooth curveto entry (S)
1906 if(mbRelative)
1908 if(aLastCommand != sal_Unicode('s'))
1909 aNewString += rtl::OUString(static_cast<sal_Unicode>('s'));
1911 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1912 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1913 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1914 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1916 aLastCommand = sal_Unicode('s');
1918 else
1920 if(aLastCommand != sal_Unicode('S'))
1921 aNewString += rtl::OUString(static_cast<sal_Unicode>('S'));
1923 Imp_PutNumberCharWithSpace(aNewString, nX2);
1924 Imp_PutNumberCharWithSpace(aNewString, nY2);
1925 Imp_PutNumberCharWithSpace(aNewString, nX);
1926 Imp_PutNumberCharWithSpace(aNewString, nY);
1928 aLastCommand = sal_Unicode('S');
1931 else
1933 // prepare coordinates
1934 sal_Int32 nX1, nY1;
1936 Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize,
1937 mrViewBox, bScale, bTranslate);
1939 // write a curveto entry (C)
1940 if(mbRelative)
1942 if(aLastCommand != sal_Unicode('c'))
1943 aNewString += rtl::OUString(static_cast<sal_Unicode>('c'));
1945 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX);
1946 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY);
1947 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX);
1948 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY);
1949 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
1950 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
1952 aLastCommand = sal_Unicode('c');
1954 else
1956 if(aLastCommand != sal_Unicode('C'))
1957 aNewString += rtl::OUString(static_cast<sal_Unicode>('C'));
1959 Imp_PutNumberCharWithSpace(aNewString, nX1);
1960 Imp_PutNumberCharWithSpace(aNewString, nY1);
1961 Imp_PutNumberCharWithSpace(aNewString, nX2);
1962 Imp_PutNumberCharWithSpace(aNewString, nY2);
1963 Imp_PutNumberCharWithSpace(aNewString, nX);
1964 Imp_PutNumberCharWithSpace(aNewString, nY);
1966 aLastCommand = sal_Unicode('C');
1971 // remember that current point IS written
1972 bDidWriteAsCurve = true;
1974 // remember new last position
1975 mnLastX = nX;
1976 mnLastY = nY;
1983 if(!bDidWriteAsCurve)
1985 // current point not yet written, prepare coordinates
1986 sal_Int32 nX, nY;
1988 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize,
1989 mrViewBox, bScale, bTranslate);
1991 if(bDidWriteStart)
1993 // write as normal point
1994 if(mnLastX == nX)
1996 if(mbRelative)
1998 if(aLastCommand != sal_Unicode('v'))
1999 aNewString += rtl::OUString(static_cast<sal_Unicode>('v'));
2001 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2003 aLastCommand = sal_Unicode('v');
2005 else
2007 if(aLastCommand != sal_Unicode('V'))
2008 aNewString += rtl::OUString(static_cast<sal_Unicode>('V'));
2010 Imp_PutNumberCharWithSpace(aNewString, nY);
2012 aLastCommand = sal_Unicode('V');
2015 else if(mnLastY == nY)
2017 if(mbRelative)
2019 if(aLastCommand != sal_Unicode('h'))
2020 aNewString += rtl::OUString(static_cast<sal_Unicode>('h'));
2022 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2024 aLastCommand = sal_Unicode('h');
2026 else
2028 if(aLastCommand != sal_Unicode('H'))
2029 aNewString += rtl::OUString(static_cast<sal_Unicode>('H'));
2031 Imp_PutNumberCharWithSpace(aNewString, nX);
2033 aLastCommand = sal_Unicode('H');
2036 else
2038 if(mbRelative)
2040 if(aLastCommand != sal_Unicode('l'))
2041 aNewString += rtl::OUString(static_cast<sal_Unicode>('l'));
2043 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2044 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2046 aLastCommand = sal_Unicode('l');
2048 else
2050 if(aLastCommand != sal_Unicode('L'))
2051 aNewString += rtl::OUString(static_cast<sal_Unicode>('L'));
2053 Imp_PutNumberCharWithSpace(aNewString, nX);
2054 Imp_PutNumberCharWithSpace(aNewString, nY);
2056 aLastCommand = sal_Unicode('L');
2060 else
2062 // write as start point
2063 if(mbRelative)
2065 aNewString += rtl::OUString(static_cast<sal_Unicode>('m'));
2067 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX);
2068 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY);
2070 aLastCommand = sal_Unicode('l');
2072 else
2074 aNewString += rtl::OUString(static_cast<sal_Unicode>('M'));
2076 Imp_PutNumberCharWithSpace(aNewString, nX);
2077 Imp_PutNumberCharWithSpace(aNewString, nY);
2079 aLastCommand = sal_Unicode('L');
2082 // remember start written
2083 bDidWriteStart = true;
2084 nStartX = nX;
2085 nStartY = nY;
2088 // remember new last position
2089 mnLastX = nX;
2090 mnLastY = nY;
2094 // next point
2095 pPointArray++;
2096 pFlagArray++;
2099 // close path if closed poly
2100 if(bClosed)
2102 if(mbRelative)
2103 aNewString += rtl::OUString(static_cast<sal_Unicode>('z'));
2104 else
2105 aNewString += rtl::OUString(static_cast<sal_Unicode>('Z'));
2107 // update current point - we're back at the start
2108 if( bDidWriteStart )
2110 mnLastX = nStartX;
2111 mnLastY = nStartY;
2115 // append new string
2116 msString += aNewString;
2120 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew,
2121 const SdXMLImExViewBox& rViewBox,
2122 const awt::Point& rObjectPos,
2123 const awt::Size& rObjectSize,
2124 const SvXMLImport& rImport)
2125 : msString( rNew ),
2126 mrViewBox( rViewBox ),
2127 mbIsClosed( false ),
2128 mbIsCurve( false ),
2129 mbRelative( true ),
2130 mnLastX( 0L ),
2131 mnLastY( 0L ),
2132 maPoly()
2134 bool bWrongPositionAfterZ( false );
2135 sal_Int32 nUPD( 0 );
2136 sal_Int32 nBuildId( 0 );
2137 if ( rImport.getBuildIds( nUPD, nBuildId ) &&
2138 ( ( nUPD == 641 ) || ( nUPD == 645 ) || ( nUPD == 680 ) || ( nUPD == 300 ) ||
2139 ( nUPD == 310 ) || ( nUPD == 320 ) || ( nUPD == 330 ) || ( nUPD == 340 ) ||
2140 ( nUPD == 350 && nBuildId < 202 ) ) )
2142 bWrongPositionAfterZ = true;
2145 // convert string to polygon
2146 basegfx::B2DPolyPolygon aPoly;
2147 basegfx::tools::importFromSvgD(aPoly,msString,bWrongPositionAfterZ);
2149 mbIsCurve = aPoly.areControlPointsUsed();
2150 mbIsClosed = aPoly.isClosed();
2152 // object size and ViewBox size different?
2153 basegfx::B2DHomMatrix aTransform;
2154 const bool bScale(rObjectSize.Width != mrViewBox.GetWidth()
2155 || rObjectSize.Height != mrViewBox.GetHeight());
2156 const bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L);
2158 if( bTranslate )
2159 aTransform.translate(
2160 -mrViewBox.GetX(),
2161 -mrViewBox.GetY());
2162 if( bScale )
2163 aTransform.scale(
2164 (mrViewBox.GetWidth() ? rObjectSize.Width / mrViewBox.GetWidth() : 0),
2165 (mrViewBox.GetHeight() ? rObjectSize.Height / mrViewBox.GetHeight() : 0));
2166 aTransform.translate( rObjectPos.X, rObjectPos.Y );
2167 aPoly.transform(aTransform);
2169 basegfx::unotools::b2DPolyPolygonToPolyPolygonBezier(aPoly,maPoly);
2172 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */