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