1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 //////////////////////////////////////////////////////////////////////////////
44 #define BORDER_INTEGERS_ARE_EQUAL (4)
46 //////////////////////////////////////////////////////////////////////////////
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()));
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
)
70 && sal_Unicode(' ') == rStr
[rPos
])
74 void Imp_SkipSpacesAndOpeningBraces(const OUString
& rStr
, sal_Int32
& rPos
, const sal_Int32 nLen
)
77 && (sal_Unicode(' ') == rStr
[rPos
] || sal_Unicode('(') == rStr
[rPos
]))
81 void Imp_SkipSpacesAndCommas(const OUString
& rStr
, sal_Int32
& rPos
, const sal_Int32 nLen
)
84 && (sal_Unicode(' ') == rStr
[rPos
] || sal_Unicode(',') == rStr
[rPos
]))
88 void Imp_SkipSpacesAndClosingBraces(const OUString
& rStr
, sal_Int32
& rPos
, const sal_Int32 nLen
)
91 && (sal_Unicode(' ') == rStr
[rPos
] || sal_Unicode(')') == rStr
[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
)
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
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;
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());
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
];
227 Imp_SkipSpaces(rStr
, rPos
, nLen
);
228 while(rPos
< nLen
&& Imp_IsOnUnitChar(rStr
, rPos
))
229 sNumberString
.append(rStr
[rPos
++]);
232 if(sNumberString
.getLength())
235 rConv
.convertDouble(fRetval
, sNumberString
.makeStringAndClear(), true);
238 ::sax::Converter::convertDouble(fRetval
,
239 sNumberString
.makeStringAndClear());
246 void Imp_PutDoubleChar(OUString
& rStr
, const SvXMLUnitConverter
& rConv
, double fValue
,
247 bool bConvertUnits
= false)
249 OUStringBuffer sStringBuffer
;
252 rConv
.convertDouble(sStringBuffer
, fValue
, true);
255 ::sax::Converter::convertDouble(sStringBuffer
, fValue
);
258 rStr
+= OUString(sStringBuffer
.makeStringAndClear());
261 //////////////////////////////////////////////////////////////////////////////
262 //////////////////////////////////////////////////////////////////////////////
263 // base class of all 2D transform objects
265 struct ImpSdXMLExpTransObj2DBase
268 ImpSdXMLExpTransObj2DBase(sal_uInt16 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
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
306 ImpSdXMLExpTransObj2DSkewX(double fVal
)
307 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX
), mfSkewX(fVal
) {}
309 struct ImpSdXMLExpTransObj2DSkewY
: public ImpSdXMLExpTransObj2DBase
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
];
335 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE
:
337 delete (ImpSdXMLExpTransObj2DRotate
*)pObj
;
340 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE
:
342 delete (ImpSdXMLExpTransObj2DScale
*)pObj
;
345 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE
:
347 delete (ImpSdXMLExpTransObj2DTranslate
*)pObj
;
350 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX
:
352 delete (ImpSdXMLExpTransObj2DSkewX
*)pObj
;
355 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY
:
357 delete (ImpSdXMLExpTransObj2DSkewY
*)pObj
;
360 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX
:
362 delete (ImpSdXMLExpTransObj2DMatrix
*)pObj
;
367 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
376 //////////////////////////////////////////////////////////////////////////////
379 void SdXMLImExTransform2D::AddRotate(double fNew
)
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
)
394 maList
.push_back(new ImpSdXMLExpTransObj2DSkewX(fNew
));
397 //////////////////////////////////////////////////////////////////////////////
398 // gen string for export
399 const OUString
& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter
& rConv
)
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
];
411 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE
:
413 aNewString
+= OUString( "rotate (" );
414 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DRotate
*)pObj
)->mfRotate
);
415 aNewString
+= aClosingBrace
;
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
;
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
;
436 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX
:
438 aNewString
+= OUString( "skewX (" );
439 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DSkewX
*)pObj
)->mfSkewX
);
440 aNewString
+= aClosingBrace
;
443 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY
:
445 aNewString
+= OUString( "skewY (" );
446 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DSkewY
*)pObj
)->mfSkewY
);
447 aNewString
+= aClosingBrace
;
450 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX
:
452 aNewString
+= OUString( "matrix (" );
455 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(0, 0));
456 aNewString
+= aEmptySpace
;
459 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(1, 0));
460 aNewString
+= aEmptySpace
;
463 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(0, 1));
464 aNewString
+= aEmptySpace
;
467 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(1, 1));
468 aNewString
+= aEmptySpace
;
471 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(0, 2), true);
472 aNewString
+= aEmptySpace
;
475 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
.get(1, 2), true);
477 aNewString
+= aClosingBrace
;
482 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
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
;
500 //////////////////////////////////////////////////////////////////////////////
501 // sets new string, parses it and generates entries
502 void SdXMLImExTransform2D::SetString(const OUString
& rNew
, const SvXMLUnitConverter
& rConv
)
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" );
524 Imp_SkipSpaces(aStr
, nPos
, nLen
);
529 if(nPos
== aStr
.indexOf(aString_rotate
, nPos
))
533 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
534 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
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);
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
;
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
))
572 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
573 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
575 maList
.push_back(new ImpSdXMLExpTransObj2DSkewX(fValue
));
577 Imp_SkipSpacesAndClosingBraces(aStr
, nPos
, nLen
);
579 else if(nPos
== aStr
.indexOf(aString_skewY
, nPos
))
583 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
584 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
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
;
595 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
598 aValue
.set(0, 0, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 0)));
599 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
602 aValue
.set(1, 0, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 0)));
603 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
606 aValue
.set(0, 1, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 1)));
607 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
610 aValue
.set(1, 1, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 1)));
611 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
614 aValue
.set(0, 2, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 2), true));
615 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
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
);
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
];
645 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE
:
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);
656 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE
:
658 const ::basegfx::B2DTuple
& rScale
= ((ImpSdXMLExpTransObj2DScale
*)pObj
)->maScale
;
659 rFullTrans
.scale(rScale
.getX(), rScale
.getY());
662 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE
:
664 const ::basegfx::B2DTuple
& rTranslate
= ((ImpSdXMLExpTransObj2DTranslate
*)pObj
)->maTranslate
;
665 rFullTrans
.translate(rTranslate
.getX(), rTranslate
.getY());
668 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX
:
670 rFullTrans
.shearX(tan(((ImpSdXMLExpTransObj2DSkewX
*)pObj
)->mfSkewX
));
673 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY
:
675 rFullTrans
.shearY(tan(((ImpSdXMLExpTransObj2DSkewY
*)pObj
)->mfSkewY
));
678 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX
:
680 rFullTrans
*= ((ImpSdXMLExpTransObj2DMatrix
*)pObj
)->maMatrix
;
685 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
692 //////////////////////////////////////////////////////////////////////////////
693 //////////////////////////////////////////////////////////////////////////////
694 // base class of all 3D transform objects
696 struct ImpSdXMLExpTransObj3DBase
699 ImpSdXMLExpTransObj3DBase(sal_uInt16 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
719 ImpSdXMLExpTransObj3DRotateX(double fVal
)
720 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X
), mfRotateX(fVal
) {}
722 struct ImpSdXMLExpTransObj3DRotateY
: public ImpSdXMLExpTransObj3DBase
725 ImpSdXMLExpTransObj3DRotateY(double fVal
)
726 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y
), mfRotateY(fVal
) {}
728 struct ImpSdXMLExpTransObj3DRotateZ
: public ImpSdXMLExpTransObj3DBase
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
];
766 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X
:
768 delete (ImpSdXMLExpTransObj3DRotateX
*)pObj
;
771 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y
:
773 delete (ImpSdXMLExpTransObj3DRotateY
*)pObj
;
776 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z
:
778 delete (ImpSdXMLExpTransObj3DRotateZ
*)pObj
;
781 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE
:
783 delete (ImpSdXMLExpTransObj3DScale
*)pObj
;
786 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE
:
788 delete (ImpSdXMLExpTransObj3DTranslate
*)pObj
;
791 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX
:
793 delete (ImpSdXMLExpTransObj3DMatrix
*)pObj
;
798 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
807 //////////////////////////////////////////////////////////////////////////////
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
)
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
];
850 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X
:
852 aNewString
+= OUString( "rotatex (" );
853 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DRotateX
*)pObj
)->mfRotateX
);
854 aNewString
+= aClosingBrace
;
857 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y
:
859 aNewString
+= OUString( "rotatey (" );
860 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DRotateY
*)pObj
)->mfRotateY
);
861 aNewString
+= aClosingBrace
;
864 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z
:
866 aNewString
+= OUString( "rotatez (" );
867 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DRotateZ
*)pObj
)->mfRotateZ
);
868 aNewString
+= aClosingBrace
;
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
;
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
;
893 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX
:
895 aNewString
+= OUString( "matrix (" );
898 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(0, 0));
899 aNewString
+= aEmptySpace
;
902 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(1, 0));
903 aNewString
+= aEmptySpace
;
906 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(2, 0));
907 aNewString
+= aEmptySpace
;
910 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(0, 1));
911 aNewString
+= aEmptySpace
;
914 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(1, 1));
915 aNewString
+= aEmptySpace
;
918 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(2, 1));
919 aNewString
+= aEmptySpace
;
922 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(0, 2));
923 aNewString
+= aEmptySpace
;
926 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(1, 2));
927 aNewString
+= aEmptySpace
;
930 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(2, 2));
931 aNewString
+= aEmptySpace
;
934 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(0, 3), true);
935 aNewString
+= aEmptySpace
;
938 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(1, 3), true);
939 aNewString
+= aEmptySpace
;
942 Imp_PutDoubleChar(aNewString
, rConv
, ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
.get(2, 3), true);
944 aNewString
+= aClosingBrace
;
949 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
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
;
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
)
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" );
998 Imp_SkipSpaces(aStr
, nPos
, nLen
);
1003 if(nPos
== aStr
.indexOf(aString_rotatex
, nPos
))
1008 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
1009 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
1011 maList
.push_back(new ImpSdXMLExpTransObj3DRotateX(fValue
));
1013 Imp_SkipSpacesAndClosingBraces(aStr
, nPos
, nLen
);
1015 else if(nPos
== aStr
.indexOf(aString_rotatey
, nPos
))
1020 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
1021 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
1023 maList
.push_back(new ImpSdXMLExpTransObj3DRotateY(fValue
));
1025 Imp_SkipSpacesAndClosingBraces(aStr
, nPos
, nLen
);
1027 else if(nPos
== aStr
.indexOf(aString_rotatez
, nPos
))
1032 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
1033 fValue
= Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, fValue
);
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);
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
;
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
;
1078 Imp_SkipSpacesAndOpeningBraces(aStr
, nPos
, nLen
);
1081 aValue
.set(0, 0, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 0)));
1082 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1085 aValue
.set(1, 0, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 0)));
1086 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1089 aValue
.set(2, 0, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(2, 0)));
1090 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1093 aValue
.set(0, 1, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 1)));
1094 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1097 aValue
.set(1, 1, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 1)));
1098 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1101 aValue
.set(2, 1, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(2, 1)));
1102 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1105 aValue
.set(0, 2, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 2)));
1106 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1109 aValue
.set(1, 2, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 2)));
1110 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1113 aValue
.set(2, 2, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(2, 2)));
1114 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1117 aValue
.set(0, 3, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(0, 3), true));
1118 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
1121 aValue
.set(1, 3, Imp_GetDoubleChar(aStr
, nPos
, nLen
, rConv
, aValue
.get(1, 3), true));
1122 Imp_SkipSpacesAndCommas(aStr
, nPos
, nLen
);
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
);
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);
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);
1190 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y
:
1192 rFullTrans
.rotate(0.0, ((ImpSdXMLExpTransObj3DRotateY
*)pObj
)->mfRotateY
, 0.0);
1195 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z
:
1197 rFullTrans
.rotate(0.0, 0.0, ((ImpSdXMLExpTransObj3DRotateZ
*)pObj
)->mfRotateZ
);
1200 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE
:
1202 const ::basegfx::B3DTuple
& rScale
= ((ImpSdXMLExpTransObj3DScale
*)pObj
)->maScale
;
1203 rFullTrans
.scale(rScale
.getX(), rScale
.getY(), rScale
.getZ());
1206 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE
:
1208 const ::basegfx::B3DTuple
& rTranslate
= ((ImpSdXMLExpTransObj3DTranslate
*)pObj
)->maTranslate
;
1209 rFullTrans
.translate(rTranslate
.getX(), rTranslate
.getY(), rTranslate
.getZ());
1212 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX
:
1214 rFullTrans
*= ((ImpSdXMLExpTransObj3DMatrix
*)pObj
)->maMatrix
;
1219 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
1226 //////////////////////////////////////////////////////////////////////////////
1227 //////////////////////////////////////////////////////////////////////////////
1229 SdXMLImExViewBox::SdXMLImExViewBox(sal_Int32 nX
, sal_Int32 nY
, sal_Int32 nW
, sal_Int32 nH
)
1237 // #100617# Asked vincent hardy: svg:viewBox values may be double precision.
1238 SdXMLImExViewBox::SdXMLImExViewBox(const OUString
& rNew
, const SvXMLUnitConverter
& rConv
)
1245 if(!msString
.isEmpty())
1247 const OUString
aStr(msString
.getStr(), (sal_uInt16
)msString
.getLength());
1248 const sal_Int32
nLen(aStr
.getLength());
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
);
1294 msString
= aNewString
;
1299 //////////////////////////////////////////////////////////////////////////////
1300 //////////////////////////////////////////////////////////////////////////////
1302 SdXMLImExPointsElement::SdXMLImExPointsElement(drawing::PointSequence
* pPoints
,
1303 const SdXMLImExViewBox
& rViewBox
,
1304 const awt::Point
& rObjectPos
,
1305 const awt::Size
& rObjectSize
,
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
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
))
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
;
1345 nX
+= rViewBox
.GetX();
1346 nY
+= rViewBox
.GetY();
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
);
1356 aNewString
+= rtl::OUString(static_cast<sal_Unicode
>(' '));
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
)
1376 // convert string to polygon
1377 const OUString
aStr(msString
.getStr(), (sal_uInt16
)msString
.getLength());
1378 const sal_Int32
nLen(aStr
.getLength());
1380 sal_Int32
nNumPoints(0L);
1382 // skip starting spaces
1383 Imp_SkipSpaces(aStr
, nPos
, nLen
);
1385 // count points in first loop
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
);
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
);
1423 // prepare new parameter pair
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
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();
1456 *pInnerSequence
= awt::Point( nX
, nY
);
1462 //////////////////////////////////////////////////////////////////////////////
1463 //////////////////////////////////////////////////////////////////////////////
1465 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const SdXMLImExViewBox
& rViewBox
,
1466 const SvXMLExport
& rExport
)
1467 : mrViewBox( rViewBox
),
1468 mbIsClosed( 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
),
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
)
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
));
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
;
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
,
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
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
1557 sal_Int32
nFlagCnt(pFlags
->getLength());
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
++)
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
))
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)))
1602 // no curve, ignore last point
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);
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);
1649 // prepare coordinates
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));
1672 nDist
+= abs(nPX_L
- nPX_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
1691 bIsQuadratic
= false;
1693 if(pPrevPos1
->X
== pPrevPos2
->X
&& pPrevPos1
->Y
== pPrevPos2
->Y
)
1694 bIsQuadratic
= true;
1696 #endif // TEST_QUADRATIC_CURVES
1700 #ifdef TEST_QUADRATIC_CURVES
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)
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');
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');
1748 // prepare coordinates
1751 Imp_PrepareCoorExport(nX1
, nY1
, pPrevPos1
, rObjectPos
, rObjectSize
,
1752 mrViewBox
, bScale
, bTranslate
);
1754 // write a quadratic curveto entry (Q)
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');
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');
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)
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');
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');
1840 // prepare coordinates
1843 Imp_PrepareCoorExport(nX1
, nY1
, &aNewPoint
, rObjectPos
, rObjectSize
,
1844 mrViewBox
, bScale
, bTranslate
);
1846 // write a quadratic curveto entry (Q)
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');
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
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
1900 Imp_PrepareCoorExport(nX2
, nY2
, pPrevPos1
, rObjectPos
, rObjectSize
,
1901 mrViewBox
, bScale
, bTranslate
);
1903 if(bPrevPointIsSymmetric
)
1905 // write a shorthand/smooth curveto entry (S)
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');
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');
1933 // prepare coordinates
1936 Imp_PrepareCoorExport(nX1
, nY1
, pPrevPos2
, rObjectPos
, rObjectSize
,
1937 mrViewBox
, bScale
, bTranslate
);
1939 // write a curveto entry (C)
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');
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
1983 if(!bDidWriteAsCurve
)
1985 // current point not yet written, prepare coordinates
1988 Imp_PrepareCoorExport(nX
, nY
, pPointArray
, rObjectPos
, rObjectSize
,
1989 mrViewBox
, bScale
, bTranslate
);
1993 // write as normal point
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');
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
)
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');
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');
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');
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');
2062 // write as start point
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');
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;
2088 // remember new last position
2099 // close path if closed poly
2103 aNewString
+= rtl::OUString(static_cast<sal_Unicode
>('z'));
2105 aNewString
+= rtl::OUString(static_cast<sal_Unicode
>('Z'));
2107 // update current point - we're back at the start
2108 if( bDidWriteStart
)
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
)
2126 mrViewBox( rViewBox
),
2127 mbIsClosed( false ),
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);
2159 aTransform
.translate(
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: */