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