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 1626 // #121090# only reduce double start/end points if polygon *is* closed 1627 if(bClosed && (pPointArray->X == (pPointArray + (nCnt - 1))->X) && (pPointArray->Y == (pPointArray + (nCnt - 1))->Y)) 1628 { 1629 if(pFlags) 1630 { 1631 // point needs to be ignored if point before it is 1632 // NO control point. Else the last point is needed 1633 // for exporting the last segment of the curve. That means 1634 // that the last and the first point will be saved double, 1635 // but SVG does not support a better solution here. 1636 if(nCnt >= 2 && drawing::PolygonFlags_CONTROL != *(pFlagArray + (nCnt - 2))) 1637 { 1638 nCnt--; 1639 } 1640 } 1641 else 1642 { 1643 // no curve, ignore last point 1644 nCnt--; 1645 } 1646 } 1647 1648 // bezier poly, handle curves 1649 bool bDidWriteStart(false); 1650 1651 for(sal_Int32 a(0L); a < nCnt; a++) 1652 { 1653 if(!pFlags || drawing::PolygonFlags_CONTROL != *pFlagArray) 1654 { 1655 bool bDidWriteAsCurve(false); 1656 1657 if(bDidWriteStart) 1658 { 1659 if(pFlags) 1660 { 1661 // real curve point, get previous to see if it's a control point 1662 awt::Point* pPrevPos1; 1663 drawing::PolygonFlags aPrevFlag1; 1664 1665 Imp_GetPrevPos(pPrevPos1, aPrevFlag1, bClosed, pPoints->getArray(), 1666 pFlags->getArray(), a, nCnt, 1); 1667 1668 if(pPrevPos1 && drawing::PolygonFlags_CONTROL == aPrevFlag1) 1669 { 1670 // get previous2 to see if it's a control point, too 1671 awt::Point* pPrevPos2; 1672 drawing::PolygonFlags aPrevFlag2; 1673 1674 Imp_GetPrevPos(pPrevPos2, aPrevFlag2, bClosed, pPoints->getArray(), 1675 pFlags->getArray(), a, nCnt, 2); 1676 1677 if(pPrevPos2 && drawing::PolygonFlags_CONTROL == aPrevFlag2) 1678 { 1679 // get previous3 to see if it's a curve point and if, 1680 // if it is fully symmetric or not 1681 awt::Point* pPrevPos3; 1682 drawing::PolygonFlags aPrevFlag3; 1683 1684 Imp_GetPrevPos(pPrevPos3, aPrevFlag3, bClosed, pPoints->getArray(), 1685 pFlags->getArray(), a, nCnt, 3); 1686 1687 if(pPrevPos3) 1688 { 1689 // prepare coordinates 1690 sal_Int32 nX, nY; 1691 1692 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize, 1693 mrViewBox, bScale, bTranslate); 1694 1695 // #100617# test if this curve segment may be written as 1696 // a quadratic bezier 1697 // That's the case if both control points are in the same place 1698 // when they are prolonged to the common quadratic control point 1699 // Left: P = (3P1 - P0) / 2 1700 // Right: P = (3P2 - P3) / 2 1701 bool bIsQuadratic(false); 1702 const bool bEnableSaveQuadratic(false); 1703 1704 sal_Int32 nPX_L(FRound((double)((3 * pPrevPos2->X) - pPrevPos3->X) / 2.0)); 1705 sal_Int32 nPY_L(FRound((double)((3 * pPrevPos2->Y) - pPrevPos3->Y) / 2.0)); 1706 sal_Int32 nPX_R(FRound((double)((3 * pPrevPos1->X) - pPointArray->X) / 2.0)); 1707 sal_Int32 nPY_R(FRound((double)((3 * pPrevPos1->Y) - pPointArray->Y) / 2.0)); 1708 sal_Int32 nDist(0); 1709 1710 if(nPX_L != nPX_R) 1711 { 1712 nDist += abs(nPX_L - nPX_R); 1713 } 1714 1715 if(nPY_L != nPY_R) 1716 { 1717 nDist += abs(nPY_L - nPY_R); 1718 } 1719 1720 if(nDist <= BORDER_INTEGERS_ARE_EQUAL) 1721 { 1722 if(bEnableSaveQuadratic) 1723 { 1724 bIsQuadratic = true; 1725 } 1726 } 1727 1728 #ifdef TEST_QUADRATIC_CURVES 1729 if(bDoTestHere) 1730 { 1731 bIsQuadratic = false; 1732 1733 if(pPrevPos1->X == pPrevPos2->X && pPrevPos1->Y == pPrevPos2->Y) 1734 bIsQuadratic = true; 1735 } 1736 #endif // TEST_QUADRATIC_CURVES 1737 1738 if(bIsQuadratic) 1739 { 1740 #ifdef TEST_QUADRATIC_CURVES 1741 if(bDoTestHere) 1742 { 1743 bool bPrevPointIsSymmetric(false); 1744 1745 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3) 1746 { 1747 // get previous4 to see if it's a control point 1748 awt::Point* pPrevPos4; 1749 drawing::PolygonFlags aPrevFlag4; 1750 1751 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), 1752 pFlags->getArray(), a, nCnt, 4); 1753 1754 if(drawing::PolygonFlags_CONTROL == aPrevFlag4) 1755 { 1756 // okay, prevPos3 is symmetric (c2) and prevPos4 1757 // is existing control point, the 's' statement can be used 1758 bPrevPointIsSymmetric = true; 1759 } 1760 } 1761 1762 if(bPrevPointIsSymmetric) 1763 { 1764 // write a shorthand/smooth quadratic curveto entry (T) 1765 if(bRelative) 1766 { 1767 if(aLastCommand != sal_Unicode('t')) 1768 aNewString += OUString(sal_Unicode('t')); 1769 1770 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1771 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1772 1773 aLastCommand = sal_Unicode('t'); 1774 } 1775 else 1776 { 1777 if(aLastCommand != sal_Unicode('T')) 1778 aNewString += OUString(sal_Unicode('T')); 1779 1780 Imp_PutNumberCharWithSpace(aNewString, nX); 1781 Imp_PutNumberCharWithSpace(aNewString, nY); 1782 1783 aLastCommand = sal_Unicode('T'); 1784 } 1785 } 1786 else 1787 { 1788 // prepare coordinates 1789 sal_Int32 nX1, nY1; 1790 1791 Imp_PrepareCoorExport(nX1, nY1, pPrevPos1, rObjectPos, rObjectSize, 1792 mrViewBox, bScale, bTranslate); 1793 1794 // write a quadratic curveto entry (Q) 1795 if(bRelative) 1796 { 1797 if(aLastCommand != sal_Unicode('q')) 1798 aNewString += OUString(sal_Unicode('q')); 1799 1800 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); 1801 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); 1802 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1803 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1804 1805 aLastCommand = sal_Unicode('q'); 1806 } 1807 else 1808 { 1809 if(aLastCommand != sal_Unicode('Q')) 1810 aNewString += OUString(sal_Unicode('Q')); 1811 1812 Imp_PutNumberCharWithSpace(aNewString, nX1); 1813 Imp_PutNumberCharWithSpace(aNewString, nY1); 1814 Imp_PutNumberCharWithSpace(aNewString, nX); 1815 Imp_PutNumberCharWithSpace(aNewString, nY); 1816 1817 aLastCommand = sal_Unicode('Q'); 1818 } 1819 } 1820 } 1821 else 1822 { 1823 #endif // TEST_QUADRATIC_CURVES 1824 awt::Point aNewPoint(nPX_L, nPY_L); 1825 bool bPrevPointIsSmooth(false); 1826 1827 if(drawing::PolygonFlags_SMOOTH == aPrevFlag3) 1828 { 1829 // get previous4 to see if it's a control point 1830 awt::Point* pPrevPos4; 1831 drawing::PolygonFlags aPrevFlag4; 1832 1833 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), 1834 pFlags->getArray(), a, nCnt, 4); 1835 1836 if(drawing::PolygonFlags_CONTROL == aPrevFlag4) 1837 { 1838 // okay, prevPos3 is smooth (c1) and prevPos4 1839 // is existing control point. Test if it's even symmetric 1840 // and thus the 'T' statement may be used. 1841 ::basegfx::B2DVector aVec1(pPrevPos4->X - pPrevPos3->X, pPrevPos4->Y - pPrevPos3->Y); 1842 ::basegfx::B2DVector aVec2(aNewPoint.X - pPrevPos3->X, aNewPoint.Y - pPrevPos3->Y); 1843 bool bSameLength(false); 1844 bool bSameDirection(false); 1845 1846 // get vector values 1847 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection); 1848 1849 if(bSameLength && bSameDirection) 1850 bPrevPointIsSmooth = true; 1851 } 1852 } 1853 1854 if(bPrevPointIsSmooth) 1855 { 1856 // write a shorthand/smooth quadratic curveto entry (T) 1857 if(bRelative) 1858 { 1859 if(aLastCommand != sal_Unicode('t')) 1860 aNewString += String(sal_Unicode('t')); 1861 1862 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1863 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1864 1865 aLastCommand = sal_Unicode('t'); 1866 } 1867 else 1868 { 1869 if(aLastCommand != sal_Unicode('T')) 1870 aNewString += String(sal_Unicode('T')); 1871 1872 Imp_PutNumberCharWithSpace(aNewString, nX); 1873 Imp_PutNumberCharWithSpace(aNewString, nY); 1874 1875 aLastCommand = sal_Unicode('T'); 1876 } 1877 } 1878 else 1879 { 1880 // prepare coordinates 1881 sal_Int32 nX1, nY1; 1882 1883 Imp_PrepareCoorExport(nX1, nY1, &aNewPoint, rObjectPos, rObjectSize, 1884 mrViewBox, bScale, bTranslate); 1885 1886 // write a quadratic curveto entry (Q) 1887 if(bRelative) 1888 { 1889 if(aLastCommand != sal_Unicode('q')) 1890 aNewString += String(sal_Unicode('q')); 1891 1892 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); 1893 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); 1894 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1895 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1896 1897 aLastCommand = sal_Unicode('q'); 1898 } 1899 else 1900 { 1901 if(aLastCommand != sal_Unicode('Q')) 1902 aNewString += String(sal_Unicode('Q')); 1903 1904 Imp_PutNumberCharWithSpace(aNewString, nX1); 1905 Imp_PutNumberCharWithSpace(aNewString, nY1); 1906 Imp_PutNumberCharWithSpace(aNewString, nX); 1907 Imp_PutNumberCharWithSpace(aNewString, nY); 1908 1909 aLastCommand = sal_Unicode('Q'); 1910 } 1911 } 1912 #ifdef TEST_QUADRATIC_CURVES 1913 } 1914 #endif // TEST_QUADRATIC_CURVES 1915 } 1916 else 1917 { 1918 bool bPrevPointIsSymmetric(false); 1919 1920 if(drawing::PolygonFlags_SYMMETRIC == aPrevFlag3) 1921 { 1922 // get previous4 to see if it's a control point 1923 awt::Point* pPrevPos4; 1924 drawing::PolygonFlags aPrevFlag4; 1925 1926 Imp_GetPrevPos(pPrevPos4, aPrevFlag4, bClosed, pPoints->getArray(), 1927 pFlags->getArray(), a, nCnt, 4); 1928 1929 if(drawing::PolygonFlags_CONTROL == aPrevFlag4) 1930 { 1931 // okay, prevPos3 is symmetric (c2) and prevPos4 1932 // is existing control point, the 's' statement can be used 1933 bPrevPointIsSymmetric = true; 1934 } 1935 } 1936 1937 // prepare coordinates 1938 sal_Int32 nX2, nY2; 1939 1940 Imp_PrepareCoorExport(nX2, nY2, pPrevPos1, rObjectPos, rObjectSize, 1941 mrViewBox, bScale, bTranslate); 1942 1943 if(bPrevPointIsSymmetric) 1944 { 1945 // write a shorthand/smooth curveto entry (S) 1946 if(bRelative) 1947 { 1948 if(aLastCommand != sal_Unicode('s')) 1949 aNewString += String(sal_Unicode('s')); 1950 1951 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX); 1952 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY); 1953 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1954 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1955 1956 aLastCommand = sal_Unicode('s'); 1957 } 1958 else 1959 { 1960 if(aLastCommand != sal_Unicode('S')) 1961 aNewString += String(sal_Unicode('S')); 1962 1963 Imp_PutNumberCharWithSpace(aNewString, nX2); 1964 Imp_PutNumberCharWithSpace(aNewString, nY2); 1965 Imp_PutNumberCharWithSpace(aNewString, nX); 1966 Imp_PutNumberCharWithSpace(aNewString, nY); 1967 1968 aLastCommand = sal_Unicode('S'); 1969 } 1970 } 1971 else 1972 { 1973 // prepare coordinates 1974 sal_Int32 nX1, nY1; 1975 1976 Imp_PrepareCoorExport(nX1, nY1, pPrevPos2, rObjectPos, rObjectSize, 1977 mrViewBox, bScale, bTranslate); 1978 1979 // write a curveto entry (C) 1980 if(bRelative) 1981 { 1982 if(aLastCommand != sal_Unicode('c')) 1983 aNewString += String(sal_Unicode('c')); 1984 1985 Imp_PutNumberCharWithSpace(aNewString, nX1 - mnLastX); 1986 Imp_PutNumberCharWithSpace(aNewString, nY1 - mnLastY); 1987 Imp_PutNumberCharWithSpace(aNewString, nX2 - mnLastX); 1988 Imp_PutNumberCharWithSpace(aNewString, nY2 - mnLastY); 1989 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 1990 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 1991 1992 aLastCommand = sal_Unicode('c'); 1993 } 1994 else 1995 { 1996 if(aLastCommand != sal_Unicode('C')) 1997 aNewString += String(sal_Unicode('C')); 1998 1999 Imp_PutNumberCharWithSpace(aNewString, nX1); 2000 Imp_PutNumberCharWithSpace(aNewString, nY1); 2001 Imp_PutNumberCharWithSpace(aNewString, nX2); 2002 Imp_PutNumberCharWithSpace(aNewString, nY2); 2003 Imp_PutNumberCharWithSpace(aNewString, nX); 2004 Imp_PutNumberCharWithSpace(aNewString, nY); 2005 2006 aLastCommand = sal_Unicode('C'); 2007 } 2008 } 2009 } 2010 2011 // remember that current point IS written 2012 bDidWriteAsCurve = true; 2013 2014 // remember new last position 2015 mnLastX = nX; 2016 mnLastY = nY; 2017 } 2018 } 2019 } 2020 } 2021 } 2022 2023 if(!bDidWriteAsCurve) 2024 { 2025 // current point not yet written, prepare coordinates 2026 sal_Int32 nX, nY; 2027 2028 Imp_PrepareCoorExport(nX, nY, pPointArray, rObjectPos, rObjectSize, 2029 mrViewBox, bScale, bTranslate); 2030 2031 if(bDidWriteStart) 2032 { 2033 // write as normal point 2034 if(mnLastX == nX) 2035 { 2036 if(bRelative) 2037 { 2038 if(aLastCommand != sal_Unicode('v')) 2039 aNewString += String(sal_Unicode('v')); 2040 2041 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 2042 2043 aLastCommand = sal_Unicode('v'); 2044 } 2045 else 2046 { 2047 if(aLastCommand != sal_Unicode('V')) 2048 aNewString += String(sal_Unicode('V')); 2049 2050 Imp_PutNumberCharWithSpace(aNewString, nY); 2051 2052 aLastCommand = sal_Unicode('V'); 2053 } 2054 } 2055 else if(mnLastY == nY) 2056 { 2057 if(bRelative) 2058 { 2059 if(aLastCommand != sal_Unicode('h')) 2060 aNewString += String(sal_Unicode('h')); 2061 2062 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 2063 2064 aLastCommand = sal_Unicode('h'); 2065 } 2066 else 2067 { 2068 if(aLastCommand != sal_Unicode('H')) 2069 aNewString += String(sal_Unicode('H')); 2070 2071 Imp_PutNumberCharWithSpace(aNewString, nX); 2072 2073 aLastCommand = sal_Unicode('H'); 2074 } 2075 } 2076 else 2077 { 2078 if(bRelative) 2079 { 2080 if(aLastCommand != sal_Unicode('l')) 2081 aNewString += String(sal_Unicode('l')); 2082 2083 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 2084 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 2085 2086 aLastCommand = sal_Unicode('l'); 2087 } 2088 else 2089 { 2090 if(aLastCommand != sal_Unicode('L')) 2091 aNewString += String(sal_Unicode('L')); 2092 2093 Imp_PutNumberCharWithSpace(aNewString, nX); 2094 Imp_PutNumberCharWithSpace(aNewString, nY); 2095 2096 aLastCommand = sal_Unicode('L'); 2097 } 2098 } 2099 } 2100 else 2101 { 2102 // write as start point 2103 if(bRelative) 2104 { 2105 aNewString += String(sal_Unicode('m')); 2106 2107 Imp_PutNumberCharWithSpace(aNewString, nX - mnLastX); 2108 Imp_PutNumberCharWithSpace(aNewString, nY - mnLastY); 2109 2110 aLastCommand = sal_Unicode('l'); 2111 } 2112 else 2113 { 2114 aNewString += String(sal_Unicode('M')); 2115 2116 Imp_PutNumberCharWithSpace(aNewString, nX); 2117 Imp_PutNumberCharWithSpace(aNewString, nY); 2118 2119 aLastCommand = sal_Unicode('L'); 2120 } 2121 2122 // remember start written 2123 bDidWriteStart = true; 2124 } 2125 2126 // remember new last position 2127 mnLastX = nX; 2128 mnLastY = nY; 2129 } 2130 } 2131 2132 // next point 2133 pPointArray++; 2134 pFlagArray++; 2135 } 2136 2137 // close path if closed poly 2138 if(bClosed) 2139 { 2140 if(bRelative) 2141 aNewString += String(sal_Unicode('z')); 2142 else 2143 aNewString += String(sal_Unicode('Z')); 2144 } 2145 2146 // append new string 2147 msString += aNewString; 2148 } 2149 } 2150 2151 // #100617# Linear double reader 2152 double Imp_ImportDoubleAndSpaces( 2153 double fRetval, const OUString& rStr, sal_Int32& rPos, 2154 const sal_Int32 nLen, const SvXMLUnitConverter& rConv) 2155 { 2156 fRetval = Imp_GetDoubleChar(rStr, rPos, nLen, rConv, fRetval); 2157 Imp_SkipSpacesAndCommas(rStr, rPos, nLen); 2158 return fRetval; 2159 } 2160 2161 // #100617# Allow to read doubles, too. This will need to be changed to 2162 // the usage of Imp_ImportDoubleAndSpaces(...). For now, this is sufficient 2163 // since the interface cannot transport doubles. 2164 sal_Int32 Imp_ImportNumberAndSpaces( 2165 sal_Int32 nRetval, const OUString& rStr, sal_Int32& rPos, 2166 const sal_Int32 nLen, const SvXMLUnitConverter& rConv) 2167 { 2168 nRetval = FRound(Imp_ImportDoubleAndSpaces(double(nRetval), rStr, rPos, nLen, rConv)); 2169 Imp_SkipSpacesAndCommas(rStr, rPos, nLen); 2170 return nRetval; 2171 } 2172 2173 void Imp_PrepareCoorImport(sal_Int32& nX, sal_Int32& nY, 2174 const awt::Point& rObjectPos, const awt::Size& rObjectSize, 2175 const SdXMLImExViewBox& rViewBox, const bool bScale, const bool bTranslate) 2176 { 2177 if(bTranslate) 2178 { 2179 nX -= rViewBox.GetX(); 2180 nY -= rViewBox.GetY(); 2181 } 2182 2183 if(bScale && rViewBox.GetWidth() && rViewBox.GetHeight()) 2184 { 2185 nX = (nX * rObjectSize.Width) / rViewBox.GetWidth(); 2186 nY = (nY * rObjectSize.Height) / rViewBox.GetHeight(); 2187 } 2188 2189 nX += rObjectPos.X; 2190 nY += rObjectPos.Y; 2191 } 2192 2193 void Imp_AddExportPoints(sal_Int32 nX, sal_Int32 nY, 2194 awt::Point* pPoints, drawing::PolygonFlags* pFlags, 2195 const sal_Int32 nInnerIndex, 2196 drawing::PolygonFlags eFlag) 2197 { 2198 if(pPoints) 2199 pPoints[nInnerIndex] = awt::Point( nX, nY ); 2200 2201 if(pFlags) 2202 pFlags[nInnerIndex] = eFlag; 2203 } 2204 2205 void Imp_CalcVectorValues(::basegfx::B2DVector& aVec1, ::basegfx::B2DVector& aVec2, bool& bSameLength, bool& bSameDirection) 2206 { 2207 const sal_Int32 nLen1(FRound(aVec1.getLength())); 2208 const sal_Int32 nLen2(FRound(aVec2.getLength())); 2209 aVec1.normalize(); 2210 aVec2.normalize(); 2211 aVec1 += aVec2; 2212 const sal_Int32 nLen3(FRound(aVec1.getLength() * ((nLen1 + nLen2) / 2.0))); 2213 2214 bSameLength = (abs(nLen1 - nLen2) <= BORDER_INTEGERS_ARE_EQUAL); 2215 bSameDirection = (nLen3 <= BORDER_INTEGERS_ARE_EQUAL); 2216 } 2217 2218 void Imp_CorrectPolygonFlag(const sal_uInt32 nInnerIndex, const awt::Point* const pInnerSequence, 2219 drawing::PolygonFlags* const pInnerFlags, const sal_Int32 nX1, const sal_Int32 nY1) 2220 { 2221 if(nInnerIndex) 2222 { 2223 const awt::Point aPPrev1 = pInnerSequence[nInnerIndex - 1]; 2224 2225 if(nInnerIndex > 1) 2226 { 2227 const awt::Point aPPrev2 = pInnerSequence[nInnerIndex - 2]; 2228 const drawing::PolygonFlags aFPrev2 = pInnerFlags[nInnerIndex - 2]; 2229 ::basegfx::B2DVector aVec1(aPPrev2.X - aPPrev1.X, aPPrev2.Y - aPPrev1.Y); 2230 ::basegfx::B2DVector aVec2(nX1 - aPPrev1.X, nY1 - aPPrev1.Y); 2231 bool bSameLength(false); 2232 bool bSameDirection(false); 2233 2234 // get vector values 2235 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection); 2236 2237 if(drawing::PolygonFlags_CONTROL == aFPrev2) 2238 { 2239 // point before is a control point 2240 if(bSameDirection) 2241 { 2242 if(bSameLength) 2243 { 2244 // set to PolygonFlags_SYMMETRIC 2245 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC; 2246 } 2247 else 2248 { 2249 // set to PolygonFlags_SMOOTH 2250 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH; 2251 } 2252 } 2253 else 2254 { 2255 // set to PolygonFlags_NORMAL 2256 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL; 2257 } 2258 } 2259 else 2260 { 2261 // point before is a simple curve point 2262 if(bSameDirection) 2263 { 2264 // set to PolygonFlags_SMOOTH 2265 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH; 2266 } 2267 else 2268 { 2269 // set to PolygonFlags_NORMAL 2270 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL; 2271 } 2272 } 2273 } 2274 else 2275 { 2276 // no point before starpoint, set type to PolygonFlags_NORMAL 2277 pInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_NORMAL; 2278 } 2279 } 2280 } 2281 2282 SdXMLImExSvgDElement::SdXMLImExSvgDElement(const OUString& rNew, 2283 const SdXMLImExViewBox& rViewBox, 2284 const awt::Point& rObjectPos, 2285 const awt::Size& rObjectSize, 2286 const SvXMLUnitConverter& rConv) 2287 : msString( rNew ), 2288 mrViewBox( rViewBox ), 2289 mbIsClosed( false ), 2290 mbIsCurve( false ), 2291 mnLastX( 0L ), 2292 mnLastY( 0L ), 2293 maPoly( 0L ), 2294 maFlag( 0L ) 2295 { 2296 // convert string to polygon 2297 const OUString aStr(msString.getStr(), msString.getLength()); 2298 const sal_Int32 nLen(aStr.getLength()); 2299 sal_Int32 nPos(0); 2300 sal_Int32 nNumPolys(0L); 2301 bool bEllipticalArc(false); 2302 2303 // object size and ViewBox size different? 2304 bool bScale(rObjectSize.Width != mrViewBox.GetWidth() 2305 || rObjectSize.Height != mrViewBox.GetHeight()); 2306 bool bTranslate(mrViewBox.GetX() != 0L || mrViewBox.GetY() != 0L); 2307 2308 // first loop: count polys and get flags 2309 Imp_SkipSpaces(aStr, nPos, nLen); 2310 2311 while(nPos < nLen) 2312 { 2313 switch(aStr[nPos++]) 2314 { 2315 case 'Z' : 2316 case 'z' : 2317 { 2318 break; 2319 } 2320 case 'M' : 2321 case 'm' : 2322 { 2323 nNumPolys++; 2324 break; 2325 } 2326 case 'S' : 2327 case 's' : 2328 case 'C' : 2329 case 'c' : 2330 case 'Q' : 2331 case 'q' : 2332 case 'T' : 2333 case 't' : 2334 { 2335 mbIsCurve = true; 2336 break; 2337 } 2338 case 'L' : 2339 case 'l' : 2340 case 'H' : 2341 case 'h' : 2342 case 'V' : 2343 case 'v' : 2344 { 2345 // normal, interpreted values. All okay. 2346 break; 2347 } 2348 case 'A' : 2349 case 'a' : 2350 { 2351 // Not yet interpreted value. 2352 bEllipticalArc = true; 2353 break; 2354 } 2355 } 2356 } 2357 2358 DBG_ASSERT(!bEllipticalArc, "XMLIMP: non-interpreted tags in svg:d element!"); 2359 2360 if(nNumPolys) 2361 { 2362 // alloc arrays 2363 maPoly.realloc(nNumPolys); 2364 if(IsCurve()) 2365 maFlag.realloc(nNumPolys); 2366 2367 // get outer sequences 2368 drawing::PointSequence* pOuterSequence = maPoly.getArray(); 2369 drawing::FlagSequence* pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L; 2370 2371 // prepare new loop, count 2372 sal_uInt32 nPointCount(0L); 2373 nPos = 0; 2374 Imp_SkipSpaces(aStr, nPos, nLen); 2375 2376 // #104076# reset closed flag for next to be started polygon 2377 mbIsClosed = false; 2378 2379 while(nPos < nLen) 2380 { 2381 switch(aStr[nPos]) 2382 { 2383 case 'z' : 2384 case 'Z' : 2385 { 2386 nPos++; 2387 Imp_SkipSpaces(aStr, nPos, nLen); 2388 2389 // #104076# remember closed state of current polygon 2390 mbIsClosed = true; 2391 2392 break; 2393 } 2394 case 'm' : 2395 case 'M' : 2396 { 2397 // new poly starts, end-process current poly 2398 if(nPointCount) 2399 { 2400 // #104076# If this partial polygon is closed, use one more point 2401 // to represent that 2402 if(mbIsClosed) 2403 { 2404 nPointCount++; 2405 } 2406 2407 pOuterSequence->realloc(nPointCount); 2408 pOuterSequence++; 2409 2410 if(pOuterFlags) 2411 { 2412 pOuterFlags->realloc(nPointCount); 2413 pOuterFlags++; 2414 } 2415 2416 // reset point count for next polygon 2417 nPointCount = 0L; 2418 } 2419 2420 // #104076# reset closed flag for next to be started polygon 2421 mbIsClosed = false; 2422 2423 // NO break, continue in next case 2424 } 2425 case 'L' : 2426 case 'l' : 2427 { 2428 nPos++; 2429 Imp_SkipSpaces(aStr, nPos, nLen); 2430 2431 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2432 { 2433 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2434 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2435 nPointCount++; 2436 } 2437 break; 2438 } 2439 case 'H' : 2440 case 'h' : 2441 case 'V' : 2442 case 'v' : 2443 { 2444 nPos++; 2445 Imp_SkipSpaces(aStr, nPos, nLen); 2446 2447 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2448 { 2449 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2450 nPointCount++; 2451 } 2452 break; 2453 } 2454 case 'S' : 2455 case 's' : 2456 { 2457 nPos++; 2458 Imp_SkipSpaces(aStr, nPos, nLen); 2459 2460 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2461 { 2462 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2463 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2464 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2465 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2466 nPointCount += 3; 2467 } 2468 break; 2469 } 2470 case 'C' : 2471 case 'c' : 2472 { 2473 nPos++; 2474 Imp_SkipSpaces(aStr, nPos, nLen); 2475 2476 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2477 { 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 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2483 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2484 nPointCount += 3; 2485 } 2486 break; 2487 } 2488 2489 // #100617# quadratic beziers, supported as cubic ones 2490 case 'Q' : 2491 case 'q' : 2492 { 2493 nPos++; 2494 Imp_SkipSpaces(aStr, nPos, nLen); 2495 2496 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2497 { 2498 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2499 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2500 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2501 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2502 2503 // use three points since quadratic is imported as cubic 2504 nPointCount += 3; 2505 } 2506 break; 2507 } 2508 2509 // #100617# relative quadratic beziers, supported as cubic ones 2510 case 'T' : 2511 case 't' : 2512 { 2513 nPos++; 2514 Imp_SkipSpaces(aStr, nPos, nLen); 2515 2516 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2517 { 2518 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2519 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2520 2521 // use three points since quadratic is imported as cubic 2522 nPointCount += 3; 2523 } 2524 break; 2525 } 2526 2527 // #100617# not yet supported: elliptical arc 2528 case 'A' : 2529 case 'a' : 2530 { 2531 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!"); 2532 nPos++; 2533 Imp_SkipSpaces(aStr, nPos, nLen); 2534 2535 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2536 { 2537 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2538 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2539 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2540 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen); 2541 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen); 2542 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2543 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2544 } 2545 break; 2546 } 2547 2548 default: 2549 { 2550 nPos++; 2551 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!"); 2552 break; 2553 } 2554 } 2555 } 2556 2557 // alloc last poly (when points used) 2558 if(nPointCount) 2559 { 2560 // #104076# If this partial polygon is closed, use one more point 2561 // to represent that 2562 if(mbIsClosed) 2563 { 2564 nPointCount++; 2565 } 2566 2567 pOuterSequence->realloc(nPointCount); 2568 pOuterSequence++; 2569 2570 if(pOuterFlags) 2571 { 2572 pOuterFlags->realloc(nPointCount); 2573 pOuterFlags++; 2574 } 2575 } 2576 2577 // set pointers back 2578 pOuterSequence = maPoly.getArray(); 2579 pOuterFlags = (IsCurve()) ? maFlag.getArray() : 0L; 2580 awt::Point* pNotSoInnerSequence = 0L; 2581 drawing::PolygonFlags* pNotSoInnerFlags = 0L; 2582 sal_uInt32 nInnerIndex(0L); 2583 2584 // prepare new loop, read points 2585 nPos = 0; 2586 Imp_SkipSpaces(aStr, nPos, nLen); 2587 2588 // #104076# reset closed flag for next to be started polygon 2589 mbIsClosed = false; 2590 2591 while(nPos < nLen) 2592 { 2593 bool bRelative(false); 2594 2595 switch(aStr[nPos]) 2596 { 2597 case 'z' : 2598 case 'Z' : 2599 { 2600 nPos++; 2601 Imp_SkipSpaces(aStr, nPos, nLen); 2602 2603 // #104076# remember closed state of current polygon 2604 mbIsClosed = true; 2605 2606 // closed: add first point again 2607 // sal_Int32 nX(pInnerSequence[0].X); 2608 // sal_Int32 nY(pInnerSequence[0].Y); 2609 // Imp_AddExportPoints(nX, nY, pInnerSequence, pInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2610 2611 break; 2612 } 2613 2614 case 'm' : 2615 { 2616 bRelative = true; 2617 } 2618 case 'M' : 2619 { 2620 // #104076# end-process current poly 2621 if(mbIsClosed) 2622 { 2623 if(pNotSoInnerSequence) 2624 { 2625 // closed: add first point again 2626 sal_Int32 nX(pNotSoInnerSequence[0].X); 2627 sal_Int32 nY(pNotSoInnerSequence[0].Y); 2628 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2629 } 2630 2631 // reset closed flag for next to be started polygon 2632 mbIsClosed = false; 2633 } 2634 2635 // next poly 2636 pNotSoInnerSequence = pOuterSequence->getArray(); 2637 pOuterSequence++; 2638 2639 if(pOuterFlags) 2640 { 2641 pNotSoInnerFlags = pOuterFlags->getArray(); 2642 pOuterFlags++; 2643 } 2644 2645 nInnerIndex = 0L; 2646 2647 nPos++; 2648 Imp_SkipSpaces(aStr, nPos, nLen); 2649 2650 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2651 { 2652 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2653 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2654 2655 if(bRelative) 2656 { 2657 nX += mnLastX; 2658 nY += mnLastY; 2659 } 2660 2661 // set last position 2662 mnLastX = nX; 2663 mnLastY = nY; 2664 2665 // calc transform and add point and flag 2666 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2667 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2668 } 2669 break; 2670 } 2671 2672 case 'l' : 2673 { 2674 bRelative = true; 2675 } 2676 case 'L' : 2677 { 2678 nPos++; 2679 Imp_SkipSpaces(aStr, nPos, nLen); 2680 2681 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2682 { 2683 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2684 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2685 2686 if(bRelative) 2687 { 2688 nX += mnLastX; 2689 nY += mnLastY; 2690 } 2691 2692 // set last position 2693 mnLastX = nX; 2694 mnLastY = nY; 2695 2696 // calc transform and add point and flag 2697 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2698 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2699 } 2700 break; 2701 } 2702 2703 case 'h' : 2704 { 2705 bRelative = true; 2706 } 2707 case 'H' : 2708 { 2709 nPos++; 2710 Imp_SkipSpaces(aStr, nPos, nLen); 2711 2712 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2713 { 2714 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2715 sal_Int32 nY(mnLastY); 2716 2717 if(bRelative) 2718 nX += mnLastX; 2719 2720 // set last position 2721 mnLastX = nX; 2722 2723 // calc transform and add point and flag 2724 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2725 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2726 } 2727 break; 2728 } 2729 2730 case 'v' : 2731 { 2732 bRelative = true; 2733 } 2734 case 'V' : 2735 { 2736 nPos++; 2737 Imp_SkipSpaces(aStr, nPos, nLen); 2738 2739 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2740 { 2741 sal_Int32 nX(mnLastX); 2742 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2743 2744 if(bRelative) 2745 nY += mnLastY; 2746 2747 // set last position 2748 mnLastY = nY; 2749 2750 // calc transform and add point and flag 2751 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2752 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 2753 } 2754 break; 2755 } 2756 2757 case 's' : 2758 { 2759 bRelative = true; 2760 } 2761 case 'S' : 2762 { 2763 nPos++; 2764 Imp_SkipSpaces(aStr, nPos, nLen); 2765 2766 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2767 { 2768 sal_Int32 nX1; 2769 sal_Int32 nY1; 2770 sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2771 sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2772 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2773 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2774 2775 if(bRelative) 2776 { 2777 nX2 += mnLastX; 2778 nY2 += mnLastY; 2779 nX += mnLastX; 2780 nY += mnLastY; 2781 } 2782 2783 // set last position 2784 mnLastX = nX; 2785 mnLastY = nY; 2786 2787 // calc transform for new points 2788 Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2789 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2790 2791 // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC 2792 // and the Point X1,Y1 can be constructed by mirroring the point before it. 2793 nX1 = nX2; 2794 nY1 = nY2; 2795 if(nInnerIndex) 2796 { 2797 awt::Point aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1]; 2798 2799 if(nInnerIndex > 1) 2800 { 2801 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2]; 2802 nX1 = aPPrev1.X -(aPPrev2.X - aPPrev1.X); 2803 nY1 = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y); 2804 } 2805 2806 // set curve point to symmetric 2807 pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SYMMETRIC; 2808 } 2809 2810 // add calculated control point 2811 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2812 2813 // add new points and set flags 2814 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2815 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH); 2816 } 2817 break; 2818 } 2819 2820 case 'c' : 2821 { 2822 bRelative = true; 2823 } 2824 case 'C' : 2825 { 2826 nPos++; 2827 Imp_SkipSpaces(aStr, nPos, nLen); 2828 2829 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2830 { 2831 sal_Int32 nX1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2832 sal_Int32 nY1(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2833 sal_Int32 nX2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2834 sal_Int32 nY2(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2835 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2836 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2837 2838 if(bRelative) 2839 { 2840 nX1 += mnLastX; 2841 nY1 += mnLastY; 2842 nX2 += mnLastX; 2843 nY2 += mnLastY; 2844 nX += mnLastX; 2845 nY += mnLastY; 2846 } 2847 2848 // set last position 2849 mnLastX = nX; 2850 mnLastY = nY; 2851 2852 // calc transform for new points 2853 Imp_PrepareCoorImport(nX1, nY1, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2854 Imp_PrepareCoorImport(nX2, nY2, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2855 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2856 2857 // correct polygon flag for previous point 2858 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1); 2859 2860 // add new points and set flags 2861 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2862 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2863 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH); 2864 } 2865 break; 2866 } 2867 2868 // #100617# quadratic beziers are imported as cubic 2869 case 'q' : 2870 { 2871 bRelative = true; 2872 } 2873 case 'Q' : 2874 { 2875 nPos++; 2876 Imp_SkipSpaces(aStr, nPos, nLen); 2877 2878 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2879 { 2880 sal_Int32 nXX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2881 sal_Int32 nYY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2882 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2883 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2884 2885 if(bRelative) 2886 { 2887 nXX += mnLastX; 2888 nYY += mnLastY; 2889 nX += mnLastX; 2890 nY += mnLastY; 2891 } 2892 2893 // set last position 2894 mnLastX = nX; 2895 mnLastY = nY; 2896 2897 // calc transform for new points 2898 Imp_PrepareCoorImport(nXX, nYY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2899 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2900 2901 // calculate X1,X2 2902 awt::Point aPPrev1 = (nInnerIndex) ? pNotSoInnerSequence[nInnerIndex-1] : pNotSoInnerSequence[0]; 2903 sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0); 2904 sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0); 2905 sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0); 2906 sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0); 2907 2908 // correct polygon flag for previous point 2909 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1); 2910 2911 // add new points and set flags 2912 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2913 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2914 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH); 2915 } 2916 break; 2917 } 2918 2919 // #100617# relative quadratic beziers are imported as cubic 2920 case 't' : 2921 { 2922 bRelative = true; 2923 } 2924 case 'T' : 2925 { 2926 nPos++; 2927 Imp_SkipSpaces(aStr, nPos, nLen); 2928 2929 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2930 { 2931 sal_Int32 nXX; 2932 sal_Int32 nYY; 2933 sal_Int32 nX(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2934 sal_Int32 nY(Imp_ImportNumberAndSpaces(0, aStr, nPos, nLen, rConv)); 2935 2936 if(bRelative) 2937 { 2938 nX += mnLastX; 2939 nY += mnLastY; 2940 } 2941 2942 // set last position 2943 mnLastX = nX; 2944 mnLastY = nY; 2945 2946 // calc transform for new points 2947 Imp_PrepareCoorImport(nX, nY, rObjectPos, rObjectSize, mrViewBox, bScale, bTranslate); 2948 2949 // one more thing is known: the previous real point is PolygonFlags_SYMMETRIC 2950 // and the Point X1,Y1 can be constructed by mirroring the point before it. 2951 nXX = nX; 2952 nYY = nY; 2953 awt::Point aPPrev1 = pNotSoInnerSequence[0]; 2954 2955 if(nInnerIndex) 2956 { 2957 aPPrev1 = pNotSoInnerSequence[nInnerIndex - 1]; 2958 2959 if(nInnerIndex > 1) 2960 { 2961 awt::Point aPPrev2 = pNotSoInnerSequence[nInnerIndex - 2]; 2962 nXX = aPPrev1.X -(aPPrev2.X - aPPrev1.X); 2963 nYY = aPPrev1.Y -(aPPrev2.Y - aPPrev1.Y); 2964 } 2965 2966 // set curve point to smooth here, since length 2967 // is changed and thus only c1 can be used. 2968 pNotSoInnerFlags[nInnerIndex - 1] = drawing::PolygonFlags_SMOOTH; 2969 } 2970 2971 // calculate X1,X2 2972 sal_Int32 nX1 = FRound((double)((nXX * 2) + aPPrev1.X) / 3.0); 2973 sal_Int32 nY1 = FRound((double)((nYY * 2) + aPPrev1.Y) / 3.0); 2974 sal_Int32 nX2 = FRound((double)((nXX * 2) + nX) / 3.0); 2975 sal_Int32 nY2 = FRound((double)((nYY * 2) + nY) / 3.0); 2976 2977 // correct polygon flag for previous point 2978 Imp_CorrectPolygonFlag(nInnerIndex, pNotSoInnerSequence, pNotSoInnerFlags, nX1, nY1); 2979 2980 // add new points and set flags 2981 Imp_AddExportPoints(nX1, nY1, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2982 Imp_AddExportPoints(nX2, nY2, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_CONTROL); 2983 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_SMOOTH); 2984 } 2985 break; 2986 } 2987 2988 // #100617# not yet supported: elliptical arc 2989 case 'A' : 2990 case 'a' : 2991 { 2992 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (elliptical arc)!"); 2993 nPos++; 2994 Imp_SkipSpaces(aStr, nPos, nLen); 2995 2996 while(nPos < nLen && Imp_IsOnNumberChar(aStr, nPos)) 2997 { 2998 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 2999 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 3000 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 3001 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen); 3002 Imp_SkipNumberAndSpacesAndCommas(aStr, nPos, nLen); 3003 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 3004 Imp_SkipDoubleAndSpacesAndCommas(aStr, nPos, nLen); 3005 } 3006 break; 3007 } 3008 3009 default: 3010 { 3011 nPos++; 3012 DBG_ERROR("XMLIMP: non-interpreted tags in svg:d element (unknown)!"); 3013 break; 3014 } 3015 } 3016 } 3017 3018 // #104076# end-process closed state of last poly 3019 if(mbIsClosed) 3020 { 3021 if(pNotSoInnerSequence) 3022 { 3023 // closed: add first point again 3024 sal_Int32 nX(pNotSoInnerSequence[0].X); 3025 sal_Int32 nY(pNotSoInnerSequence[0].Y); 3026 Imp_AddExportPoints(nX, nY, pNotSoInnerSequence, pNotSoInnerFlags, nInnerIndex++, drawing::PolygonFlags_NORMAL); 3027 } 3028 } 3029 3030 // #87202# If it's a curve and it's closed the last point maybe too much 3031 // and just exported since SVG does not allow special handling of same 3032 // start and end point, remove this last point. 3033 // Evtl. correct the last curve flags, too. 3034 if(IsCurve() && IsClosed()) 3035 { 3036 // make one more loop over the PolyPolygon 3037 pOuterSequence = maPoly.getArray(); 3038 pOuterFlags = maFlag.getArray(); 3039 sal_Int32 nOuterCnt(maPoly.getLength()); 3040 3041 for(sal_Int32 a(0); a < nOuterCnt; a++) 3042 { 3043 // get Polygon pointers 3044 awt::Point* pInnerSequence = pOuterSequence->getArray(); 3045 drawing::PolygonFlags* pInnerFlags = pOuterFlags->getArray(); 3046 sal_Int32 nInnerCnt(pOuterSequence->getLength()); 3047 3048 while( nInnerCnt >= 2 3049 && ((pInnerSequence + (nInnerCnt - 2))->X == (pInnerSequence + (nInnerCnt - 1))->X) 3050 && ((pInnerSequence + (nInnerCnt - 2))->Y == (pInnerSequence + (nInnerCnt - 1))->Y) 3051 && drawing::PolygonFlags_CONTROL != *(pInnerFlags + (nInnerCnt - 2))) 3052 { 3053 // remove last point from array 3054 pOuterSequence->realloc(nInnerCnt - 1); 3055 pOuterFlags->realloc(nInnerCnt - 1); 3056 3057 // get new pointers 3058 pInnerSequence = pOuterSequence->getArray(); 3059 pInnerFlags = pOuterFlags->getArray(); 3060 nInnerCnt = pOuterSequence->getLength(); 3061 } 3062 3063 // now evtl. correct the last curve flags 3064 if(nInnerCnt >= 4) 3065 { 3066 if( pInnerSequence->X == (pInnerSequence + (nInnerCnt - 1))->X 3067 && pInnerSequence->Y == (pInnerSequence + (nInnerCnt - 1))->Y 3068 && drawing::PolygonFlags_CONTROL == *(pInnerFlags + 1) 3069 && drawing::PolygonFlags_CONTROL == *(pInnerFlags + (nInnerCnt - 2))) 3070 { 3071 awt::Point aPrev = *(pInnerSequence + (nInnerCnt - 2)); 3072 awt::Point aCurr = *pInnerSequence; 3073 awt::Point aNext = *(pInnerSequence + 1); 3074 ::basegfx::B2DVector aVec1(aPrev.X - aCurr.X, aPrev.Y - aCurr.Y); 3075 ::basegfx::B2DVector aVec2(aNext.X - aCurr.X, aNext.Y - aCurr.Y); 3076 bool bSameLength(false); 3077 bool bSameDirection(false); 3078 3079 // get vector values 3080 Imp_CalcVectorValues(aVec1, aVec2, bSameLength, bSameDirection); 3081 3082 // set correct flag value 3083 if(bSameDirection) 3084 { 3085 if(bSameLength) 3086 { 3087 // set to PolygonFlags_SYMMETRIC 3088 *pInnerFlags = drawing::PolygonFlags_SYMMETRIC; 3089 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SYMMETRIC; 3090 } 3091 else 3092 { 3093 // set to PolygonFlags_SMOOTH 3094 *pInnerFlags = drawing::PolygonFlags_SMOOTH; 3095 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_SMOOTH; 3096 } 3097 } 3098 else 3099 { 3100 // set to PolygonFlags_NORMAL 3101 *pInnerFlags = drawing::PolygonFlags_NORMAL; 3102 *(pInnerFlags + (nInnerCnt - 1)) = drawing::PolygonFlags_NORMAL; 3103 } 3104 } 3105 } 3106 3107 // switch to next Polygon 3108 pOuterSequence++; 3109 pOuterFlags++; 3110 } 3111 } 3112 } 3113 } 3114 3115 // eof 3116