Avoid potential negative array index access to cached text.
[LibreOffice.git] / xmloff / source / draw / xexptran.cxx
blobc3ea5a4b0f708b43831339dbeba373bf5ab1c303
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 <sal/config.h>
22 #include <string_view>
24 #include <utility>
25 #include <xexptran.hxx>
26 #include <rtl/ustrbuf.hxx>
27 #include <osl/diagnose.h>
28 #include <sax/tools/converter.hxx>
29 #include <xmloff/xmluconv.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <basegfx/tuple/b2dtuple.hxx>
32 #include <basegfx/tuple/b3dtuple.hxx>
33 #include <basegfx/matrix/b3dhommatrix.hxx>
34 #include <basegfx/numeric/ftools.hxx>
35 #include <basegfx/matrix/b3dhommatrixtools.hxx>
37 using namespace ::com::sun::star;
39 // parsing help functions for simple chars
40 static void Imp_SkipSpaces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen)
42 while(rPos < nLen
43 && ' ' == rStr[rPos])
44 rPos++;
47 static void Imp_SkipSpacesAndOpeningBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen)
49 while(rPos < nLen
50 && (' ' == rStr[rPos] || '(' == rStr[rPos]))
51 rPos++;
54 static void Imp_SkipSpacesAndCommas(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen)
56 while(rPos < nLen
57 && (' ' == rStr[rPos] || ',' == rStr[rPos]))
58 rPos++;
61 static void Imp_SkipSpacesAndClosingBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen)
63 while(rPos < nLen
64 && (' ' == rStr[rPos] || ')' == rStr[rPos]))
65 rPos++;
68 // parsing help functions for integer numbers
70 static bool Imp_IsOnUnitChar(std::u16string_view rStr, const sal_Int32 nPos)
72 sal_Unicode aChar(rStr[nPos]);
74 return ('a' <= aChar && 'z' >= aChar)
75 || ('A' <= aChar && 'Z' >= aChar)
76 || '%' == aChar;
79 static double Imp_GetDoubleChar(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen,
80 const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false)
82 sal_Unicode aChar(rStr[rPos]);
83 OUStringBuffer sNumberString(32);
85 if('+' == aChar || '-' == aChar)
87 sNumberString.append(rStr[rPos]);
88 ++rPos;
89 aChar = rPos >= nLen ? 0 : rStr[rPos];
92 while(('0' <= aChar && '9' >= aChar)
93 || '.' == aChar)
95 sNumberString.append(rStr[rPos]);
96 ++rPos;
97 aChar = rPos >= nLen ? 0 : rStr[rPos];
100 if('e' == aChar || 'E' == aChar)
102 sNumberString.append(rStr[rPos]);
103 ++rPos;
104 aChar = rPos >= nLen ? 0 : rStr[rPos];
106 if('+' == aChar || '-' == aChar)
108 sNumberString.append(rStr[rPos]);
109 ++rPos;
110 aChar = rPos >= nLen ? 0 : rStr[rPos];
113 while('0' <= aChar && '9' >= aChar)
115 sNumberString.append(rStr[rPos]);
116 ++rPos;
117 aChar = rPos >= nLen ? 0 : rStr[rPos];
121 if(bLookForUnits)
123 Imp_SkipSpaces(rStr, rPos, nLen);
124 while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos))
125 sNumberString.append(rStr[rPos++]);
128 if(!sNumberString.isEmpty())
130 if(bLookForUnits)
131 rConv.convertDouble(fRetval, sNumberString);
132 else
134 ::sax::Converter::convertDouble(fRetval, sNumberString);
138 return fRetval;
141 static void Imp_PutDoubleChar(OUString& rStr, double fValue)
143 OUStringBuffer sStringBuffer;
144 ::sax::Converter::convertDouble(sStringBuffer, fValue);
145 rStr += sStringBuffer;
148 static void Imp_PutDoubleChar(OUStringBuffer& rStr, const SvXMLUnitConverter& rConv, double fValue,
149 bool bConvertUnits = false)
151 OUStringBuffer sStringBuffer;
153 if(bConvertUnits)
154 rConv.convertDouble(sStringBuffer, fValue);
155 else
157 ::sax::Converter::convertDouble(sStringBuffer, fValue);
160 rStr.append(sStringBuffer);
163 // base class of all 2D transform objects
165 struct ImpSdXMLExpTransObj2DBase
167 sal_uInt16 mnType;
168 explicit ImpSdXMLExpTransObj2DBase(sal_uInt16 nType)
169 : mnType(nType) {}
172 // possible object types for 2D
174 #define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000
175 #define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001
176 #define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002
177 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003
178 #define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004
179 #define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005
181 // classes of objects, different sizes
183 namespace {
185 struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase
187 double mfRotate;
188 explicit ImpSdXMLExpTransObj2DRotate(double fVal)
189 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {}
191 struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase
193 ::basegfx::B2DTuple maScale;
194 explicit ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew)
195 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {}
197 struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase
199 ::basegfx::B2DTuple maTranslate;
200 explicit ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew)
201 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {}
203 struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase
205 double mfSkewX;
206 explicit ImpSdXMLExpTransObj2DSkewX(double fVal)
207 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {}
209 struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase
211 double mfSkewY;
212 explicit ImpSdXMLExpTransObj2DSkewY(double fVal)
213 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {}
215 struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase
217 ::basegfx::B2DHomMatrix maMatrix;
218 explicit ImpSdXMLExpTransObj2DMatrix(::basegfx::B2DHomMatrix aNew)
219 : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(std::move(aNew)) {}
224 // add members
226 void SdXMLImExTransform2D::AddRotate(double fNew)
228 if(fNew != 0.0)
229 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DRotate>(fNew));
232 void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew)
234 if(!rNew.equalZero())
235 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DTranslate>(rNew));
238 void SdXMLImExTransform2D::AddSkewX(double fNew)
240 if(fNew != 0.0)
241 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewX>(fNew));
244 // gen string for export
245 const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv)
247 OUStringBuffer aNewString;
248 OUString aClosingBrace(")");
249 OUString aEmptySpace(" ");
251 const sal_uInt32 nCount = maList.size();
252 for(sal_uInt32 a(0); a < nCount; a++)
254 ImpSdXMLExpTransObj2DBase* pObj = maList[a].get();
255 switch(pObj->mnType)
257 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
259 aNewString.append("rotate (");
260 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DRotate*>(pObj)->mfRotate);
261 aNewString.append(aClosingBrace);
262 break;
264 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
266 aNewString.append("scale (");
267 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale.getX());
268 aNewString.append(aEmptySpace);
269 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale.getY());
270 aNewString.append(aClosingBrace);
271 break;
273 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
275 aNewString.append("translate (");
276 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate.getX(), true);
277 aNewString.append(aEmptySpace);
278 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate.getY(), true);
279 aNewString.append(aClosingBrace);
280 break;
282 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
284 aNewString.append("skewX (");
285 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DSkewX*>(pObj)->mfSkewX);
286 aNewString.append(aClosingBrace);
287 break;
289 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
291 aNewString.append("skewY (");
292 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DSkewY*>(pObj)->mfSkewY);
293 aNewString.append(aClosingBrace);
294 break;
296 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
298 aNewString.append("matrix (");
300 // a
301 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 0));
302 aNewString.append(aEmptySpace);
304 // b
305 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 0));
306 aNewString.append(aEmptySpace);
308 // c
309 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 1));
310 aNewString.append(aEmptySpace);
312 // d
313 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 1));
314 aNewString.append(aEmptySpace);
316 // e
317 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(0, 2), true);
318 aNewString.append(aEmptySpace);
320 // f
321 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix.get(1, 2), true);
323 aNewString.append(aClosingBrace);
324 break;
326 default :
328 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
329 break;
333 // if not the last entry, add one space to next tag
334 if(a + 1 != maList.size())
336 aNewString.append(aEmptySpace);
340 // fill string form OUString
341 msString = aNewString.makeStringAndClear();
343 return msString;
346 // sets new string, parses it and generates entries
347 void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
349 msString = rNew;
350 maList.clear();
352 if(msString.isEmpty())
353 return;
355 const OUString aStr = msString;
356 const sal_Int32 nLen(aStr.getLength());
358 static constexpr OUStringLiteral aString_rotate( u"rotate" );
359 static constexpr OUStringLiteral aString_scale( u"scale" );
360 static constexpr OUStringLiteral aString_translate( u"translate" );
361 static constexpr OUStringLiteral aString_skewX( u"skewX" );
362 static constexpr OUStringLiteral aString_skewY( u"skewY" );
363 static constexpr OUStringLiteral aString_matrix( u"matrix" );
365 sal_Int32 nPos(0);
367 while(nPos < nLen)
369 // skip spaces
370 Imp_SkipSpaces(aStr, nPos, nLen);
372 // look for tag
373 if(nPos < nLen)
375 if(nPos == aStr.indexOf(aString_rotate, nPos))
377 double fValue(0.0);
378 nPos += 6;
379 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
380 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
381 if(fValue != 0.0)
382 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DRotate>(fValue));
384 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
386 else if(nPos == aStr.indexOf(aString_scale, nPos))
388 ::basegfx::B2DTuple aValue(1.0, 1.0);
389 nPos += 5;
390 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
391 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
392 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
393 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
395 if(aValue.getX() != 1.0 || aValue.getY() != 1.0)
396 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DScale>(aValue));
398 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
400 else if(nPos == aStr.indexOf(aString_translate, nPos))
402 ::basegfx::B2DTuple aValue;
403 nPos += 9;
404 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
405 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
406 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
407 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
409 if(!aValue.equalZero())
410 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DTranslate>(aValue));
412 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
414 else if(nPos == aStr.indexOf(aString_skewX, nPos))
416 double fValue(0.0);
417 nPos += 5;
418 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
419 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
420 if(fValue != 0.0)
421 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewX>(fValue));
423 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
425 else if(nPos == aStr.indexOf(aString_skewY, nPos))
427 double fValue(0.0);
428 nPos += 5;
429 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
430 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
431 if(fValue != 0.0)
432 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DSkewY>(fValue));
434 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
436 else if(nPos == aStr.indexOf(aString_matrix, nPos))
438 ::basegfx::B2DHomMatrix aValue;
440 nPos += 6;
441 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
443 // a
444 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
445 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
447 // b
448 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
449 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
451 // c
452 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
453 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
455 // d
456 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
457 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
459 // e
460 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true));
461 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
463 // f
464 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true));
465 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
467 if(!aValue.isIdentity())
468 maList.push_back(std::make_shared<ImpSdXMLExpTransObj2DMatrix>(aValue));
470 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
472 else
474 nPos++;
480 void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans)
482 rFullTrans.identity();
484 const sal_uInt32 nCount = maList.size();
485 for(sal_uInt32 a(0); a < nCount; a++)
487 ImpSdXMLExpTransObj2DBase* pObj = maList[a].get();
488 switch(pObj->mnType)
490 case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE :
492 // #i78696#
493 // mfRotate is mathematically wrong oriented since we export/import the angle
494 // values mirrored. This error is fixed in the API, but not yet in the FileFormat.
495 // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next
496 // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary
497 // to mirror the value here
498 rFullTrans.rotate(static_cast<ImpSdXMLExpTransObj2DRotate*>(pObj)->mfRotate * -1.0);
499 break;
501 case IMP_SDXMLEXP_TRANSOBJ2D_SCALE :
503 const ::basegfx::B2DTuple& rScale = static_cast<ImpSdXMLExpTransObj2DScale*>(pObj)->maScale;
504 rFullTrans.scale(rScale.getX(), rScale.getY());
505 break;
507 case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE :
509 const ::basegfx::B2DTuple& rTranslate = static_cast<ImpSdXMLExpTransObj2DTranslate*>(pObj)->maTranslate;
510 rFullTrans.translate(rTranslate.getX(), rTranslate.getY());
511 break;
513 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX :
515 // For to get a mathematical correct matrix from already existing documents,
516 // mirror the value here. ODF spec is unclear about direction.
517 rFullTrans.shearX(-tan(static_cast<ImpSdXMLExpTransObj2DSkewX*>(pObj)->mfSkewX));
518 break;
520 case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY :
522 // LibreOffice does not write skewY, OOo neither. Such files are foreign documents
523 // or manually set transformations. OOo had used the value as -tan(value) before
524 // errors were introduced, Scribus 1.5.4 uses it as -tan(value) too, MS Office does
525 // not shear at all. ODF spec is unclear about direction.
526 rFullTrans.shearY(-tan(static_cast<ImpSdXMLExpTransObj2DSkewY*>(pObj)->mfSkewY));
527 break;
529 case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX :
531 rFullTrans *= static_cast<ImpSdXMLExpTransObj2DMatrix*>(pObj)->maMatrix;
532 break;
534 default :
536 OSL_FAIL("SdXMLImExTransform2D: impossible entry!");
537 break;
543 // base class of all 3D transform objects
545 struct ImpSdXMLExpTransObj3DBase
547 sal_uInt16 mnType;
548 explicit ImpSdXMLExpTransObj3DBase(sal_uInt16 nType)
549 : mnType(nType) {}
552 // possible object types for 3D
554 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000
555 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001
556 #define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002
557 #define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003
558 #define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004
559 #define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005
561 // classes of objects, different sizes
563 namespace {
565 struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase
567 double mfRotateX;
568 explicit ImpSdXMLExpTransObj3DRotateX(double fVal)
569 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {}
571 struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase
573 double mfRotateY;
574 explicit ImpSdXMLExpTransObj3DRotateY(double fVal)
575 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {}
577 struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase
579 double mfRotateZ;
580 explicit ImpSdXMLExpTransObj3DRotateZ(double fVal)
581 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {}
583 struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase
585 ::basegfx::B3DTuple maScale;
586 explicit ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew)
587 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {}
589 struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase
591 ::basegfx::B3DTuple maTranslate;
592 explicit ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew)
593 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {}
595 struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase
597 ::basegfx::B3DHomMatrix maMatrix;
598 explicit ImpSdXMLExpTransObj3DMatrix(::basegfx::B3DHomMatrix aNew)
599 : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(std::move(aNew)) {}
604 // add members
606 void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew)
608 if(!rNew.isIdentity())
609 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DMatrix>(rNew));
612 void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat)
614 AddMatrix(basegfx::utils::UnoHomogenMatrixToB3DHomMatrix(xHomMat));
617 // gen string for export
618 const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv)
620 OUStringBuffer aNewString;
621 OUString aClosingBrace(")");
622 OUString aEmptySpace(" ");
624 const sal_uInt32 nCount = maList.size();
625 for(sal_uInt32 a(0); a < nCount; a++)
627 ImpSdXMLExpTransObj3DBase* pObj = maList[a].get();
628 switch(pObj->mnType)
630 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
632 aNewString.append("rotatex (");
633 Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateX*>(pObj)->mfRotateX) );
634 aNewString.append(aClosingBrace);
635 break;
637 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
639 aNewString.append("rotatey (");
640 Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateY*>(pObj)->mfRotateY) );
641 aNewString.append(aClosingBrace);
642 break;
644 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
646 aNewString.append("rotatez (");
647 Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast<ImpSdXMLExpTransObj3DRotateZ*>(pObj)->mfRotateZ) );
648 aNewString.append(aClosingBrace);
649 break;
651 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
653 aNewString.append("scale (");
654 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getX());
655 aNewString.append(aEmptySpace);
656 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getY());
657 aNewString.append(aEmptySpace);
658 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale.getZ());
659 aNewString.append(aClosingBrace);
660 break;
662 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
664 aNewString.append("translate (");
665 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getX(), true);
666 aNewString.append(aEmptySpace);
667 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getY(), true);
668 aNewString.append(aEmptySpace);
669 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate.getZ(), true);
670 aNewString.append(aClosingBrace);
671 break;
673 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
675 aNewString.append("matrix (");
677 // a
678 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 0));
679 aNewString.append(aEmptySpace);
681 // b
682 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 0));
683 aNewString.append(aEmptySpace);
685 // c
686 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 0));
687 aNewString.append(aEmptySpace);
689 // d
690 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 1));
691 aNewString.append(aEmptySpace);
693 // e
694 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 1));
695 aNewString.append(aEmptySpace);
697 // f
698 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 1));
699 aNewString.append(aEmptySpace);
701 // g
702 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 2));
703 aNewString.append(aEmptySpace);
705 // h
706 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 2));
707 aNewString.append(aEmptySpace);
709 // i
710 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 2));
711 aNewString.append(aEmptySpace);
713 // j
714 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(0, 3), true);
715 aNewString.append(aEmptySpace);
717 // k
718 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(1, 3), true);
719 aNewString.append(aEmptySpace);
721 // l
722 Imp_PutDoubleChar(aNewString, rConv, static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix.get(2, 3), true);
724 aNewString.append(aClosingBrace);
725 break;
727 default :
729 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
730 break;
734 // if not the last entry, add one space to next tag
735 if(a + 1 != maList.size())
737 aNewString.append(aEmptySpace);
741 // fill string form OUString
742 msString = aNewString.makeStringAndClear();
744 return msString;
747 // for Import: constructor with string, parses it and generates entries
748 SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv)
750 SetString(rNew, rConv);
753 // sets new string, parses it and generates entries
754 void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv)
756 msString = rNew;
757 maList.clear();
759 if(msString.isEmpty())
760 return;
762 const OUString aStr = msString;
763 const sal_Int32 nLen(aStr.getLength());
765 static constexpr OUStringLiteral aString_rotatex( u"rotatex" );
766 static constexpr OUStringLiteral aString_rotatey( u"rotatey" );
767 static constexpr OUStringLiteral aString_rotatez( u"rotatez" );
768 static constexpr OUStringLiteral aString_scale( u"scale" );
769 static constexpr OUStringLiteral aString_translate( u"translate" );
770 static constexpr OUStringLiteral aString_matrix( u"matrix" );
772 sal_Int32 nPos(0);
774 while(nPos < nLen)
776 // skip spaces
777 Imp_SkipSpaces(aStr, nPos, nLen);
779 // look for tag
780 if(nPos < nLen)
782 if(nPos == aStr.indexOf(aString_rotatex, nPos))
784 double fValue(0.0);
786 nPos += 7;
787 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
788 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
789 if(fValue != 0.0)
790 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateX>(basegfx::deg2rad(fValue)));
792 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
794 else if(nPos == aStr.indexOf(aString_rotatey, nPos))
796 double fValue(0.0);
798 nPos += 7;
799 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
800 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
801 if(fValue != 0.0)
802 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateY>(basegfx::deg2rad(fValue)));
804 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
806 else if(nPos == aStr.indexOf(aString_rotatez, nPos))
808 double fValue(0.0);
810 nPos += 7;
811 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
812 fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue);
813 if(fValue != 0.0)
814 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DRotateZ>(basegfx::deg2rad(fValue)));
816 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
818 else if(nPos == aStr.indexOf(aString_scale, nPos))
820 ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0);
822 nPos += 5;
823 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
824 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX()));
825 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
826 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY()));
827 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
828 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ()));
830 if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ())
831 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DScale>(aValue));
833 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
835 else if(nPos == aStr.indexOf(aString_translate, nPos))
837 ::basegfx::B3DTuple aValue;
839 nPos += 9;
840 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
841 aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true));
842 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
843 aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true));
844 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
845 aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true));
847 if(!aValue.equalZero())
848 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DTranslate>(aValue));
850 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
852 else if(nPos == aStr.indexOf(aString_matrix, nPos))
854 ::basegfx::B3DHomMatrix aValue;
856 nPos += 6;
857 Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen);
859 // a
860 aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0)));
861 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
863 // b
864 aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0)));
865 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
867 // c
868 aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0)));
869 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
871 // d
872 aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1)));
873 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
875 // e
876 aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1)));
877 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
879 // f
880 aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1)));
881 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
883 // g
884 aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2)));
885 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
887 // h
888 aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2)));
889 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
891 // i
892 aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2)));
893 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
895 // j
896 aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true));
897 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
899 // k
900 aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true));
901 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
903 // l
904 aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true));
905 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
907 if(!aValue.isIdentity())
908 maList.push_back(std::make_shared<ImpSdXMLExpTransObj3DMatrix>(aValue));
910 Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen);
912 else
914 nPos++;
920 bool SdXMLImExTransform3D::GetFullHomogenTransform(css::drawing::HomogenMatrix& xHomMat)
922 ::basegfx::B3DHomMatrix aFullTransform;
923 GetFullTransform(aFullTransform);
925 if(!aFullTransform.isIdentity())
927 basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(aFullTransform, xHomMat);
928 return true;
931 return false;
934 void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans)
936 rFullTrans.identity();
938 const sal_uInt32 nCount = maList.size();
939 for(sal_uInt32 a(0); a < nCount; a++)
941 ImpSdXMLExpTransObj3DBase* pObj = maList[a].get();
942 switch(pObj->mnType)
944 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X :
946 rFullTrans.rotate(static_cast<ImpSdXMLExpTransObj3DRotateX*>(pObj)->mfRotateX, 0.0, 0.0);
947 break;
949 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y :
951 rFullTrans.rotate(0.0, static_cast<ImpSdXMLExpTransObj3DRotateY*>(pObj)->mfRotateY, 0.0);
952 break;
954 case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z :
956 rFullTrans.rotate(0.0, 0.0, static_cast<ImpSdXMLExpTransObj3DRotateZ*>(pObj)->mfRotateZ);
957 break;
959 case IMP_SDXMLEXP_TRANSOBJ3D_SCALE :
961 const ::basegfx::B3DTuple& rScale = static_cast<ImpSdXMLExpTransObj3DScale*>(pObj)->maScale;
962 rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ());
963 break;
965 case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE :
967 const ::basegfx::B3DTuple& rTranslate = static_cast<ImpSdXMLExpTransObj3DTranslate*>(pObj)->maTranslate;
968 rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ());
969 break;
971 case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX :
973 rFullTrans *= static_cast<ImpSdXMLExpTransObj3DMatrix*>(pObj)->maMatrix;
974 break;
976 default :
978 OSL_FAIL("SdXMLImExTransform3D: impossible entry!");
979 break;
985 SdXMLImExViewBox::SdXMLImExViewBox(double fX, double fY, double fW, double fH)
986 : mfX( fX ),
987 mfY( fY ),
988 mfW( fW ),
989 mfH( fH )
993 // #100617# Asked vincent hardy: svg:viewBox values may be double precision.
994 SdXMLImExViewBox::SdXMLImExViewBox(OUString aNew, const SvXMLUnitConverter& rConv)
995 : msString(std::move(aNew)),
996 mfX( 0.0 ),
997 mfY( 0.0 ),
998 mfW( 1000.0 ),
999 mfH( 1000.0 )
1001 if(msString.isEmpty())
1002 return;
1004 const OUString aStr = msString;
1005 const sal_Int32 nLen(aStr.getLength());
1006 sal_Int32 nPos(0);
1008 // skip starting spaces
1009 Imp_SkipSpaces(aStr, nPos, nLen);
1011 // get mX, #100617# be prepared for doubles
1012 mfX = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfX);
1014 // skip spaces and commas
1015 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1017 // get mY, #100617# be prepared for doubles
1018 mfY = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfY);
1020 // skip spaces and commas
1021 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1023 // get mW, #100617# be prepared for doubles
1024 mfW = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfW);
1026 // skip spaces and commas
1027 Imp_SkipSpacesAndCommas(aStr, nPos, nLen);
1029 // get mH, #100617# be prepared for doubles
1030 mfH = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfH);
1034 const OUString& SdXMLImExViewBox::GetExportString()
1036 OUString aNewString;
1037 OUString aEmptySpace(" ");
1039 Imp_PutDoubleChar(aNewString, mfX);
1040 aNewString += aEmptySpace;
1042 Imp_PutDoubleChar(aNewString, mfY);
1043 aNewString += aEmptySpace;
1045 Imp_PutDoubleChar(aNewString, mfW);
1046 aNewString += aEmptySpace;
1048 Imp_PutDoubleChar(aNewString, mfH);
1050 // set new string
1051 msString = aNewString;
1053 return msString;
1056 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */