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 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_svgio.hxx" 24 25 #include <svgio/svgreader/svggradientnode.hxx> 26 #include <svgio/svgreader/svgdocument.hxx> 27 #include <svgio/svgreader/svggradientstopnode.hxx> 28 29 ////////////////////////////////////////////////////////////////////////////// 30 31 namespace svgio 32 { 33 namespace svgreader 34 { 35 void SvgGradientNode::tryToFindLink() 36 { 37 if(!mpXLink && maXLink.getLength()) 38 { 39 mpXLink = dynamic_cast< const SvgGradientNode* >(getDocument().findSvgNodeById(maXLink)); 40 } 41 } 42 43 SvgGradientNode::SvgGradientNode( 44 SVGToken aType, 45 SvgDocument& rDocument, 46 SvgNode* pParent) 47 : SvgNode(aType, rDocument, pParent), 48 maSvgStyleAttributes(*this), 49 maX1(), 50 maY1(), 51 maX2(), 52 maY2(), 53 maCx(), 54 maCy(), 55 maR(), 56 maFx(), 57 maFy(), 58 maGradientUnits(objectBoundingBox), 59 maSpreadMethod(drawinglayer::primitive2d::Spread_pad), 60 mpaGradientTransform(0), 61 maXLink(), 62 mpXLink(0) 63 { 64 OSL_ENSURE(aType == SVGTokenLinearGradient || aType == SVGTokenRadialGradient, "SvgGradientNode should ony be used for Linear and Radial gradient (!)"); 65 } 66 67 SvgGradientNode::~SvgGradientNode() 68 { 69 if(mpaGradientTransform) delete mpaGradientTransform; 70 // do NOT delete mpXLink, it's only referenced, not owned 71 } 72 73 const SvgStyleAttributes* SvgGradientNode::getSvgStyleAttributes() const 74 { 75 static rtl::OUString aClassStrA(rtl::OUString::createFromAscii("linearGradient")); 76 static rtl::OUString aClassStrB(rtl::OUString::createFromAscii("radialGradient")); 77 78 return checkForCssStyle( 79 SVGTokenLinearGradient == getType() ? aClassStrA : aClassStrB, 80 maSvgStyleAttributes); 81 } 82 83 void SvgGradientNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 84 { 85 // call parent 86 SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 87 88 // read style attributes 89 maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 90 91 // parse own 92 switch(aSVGToken) 93 { 94 case SVGTokenStyle: 95 { 96 readLocalCssStyle(aContent); 97 break; 98 } 99 case SVGTokenX1: 100 { 101 SvgNumber aNum; 102 103 if(readSingleNumber(aContent, aNum)) 104 { 105 setX1(aNum); 106 } 107 break; 108 } 109 case SVGTokenY1: 110 { 111 SvgNumber aNum; 112 113 if(readSingleNumber(aContent, aNum)) 114 { 115 setY1(aNum); 116 } 117 break; 118 } 119 case SVGTokenX2: 120 { 121 SvgNumber aNum; 122 123 if(readSingleNumber(aContent, aNum)) 124 { 125 setX2(aNum); 126 } 127 break; 128 } 129 case SVGTokenY2: 130 { 131 SvgNumber aNum; 132 133 if(readSingleNumber(aContent, aNum)) 134 { 135 setY2(aNum); 136 } 137 break; 138 } 139 case SVGTokenCx: 140 { 141 SvgNumber aNum; 142 143 if(readSingleNumber(aContent, aNum)) 144 { 145 setCx(aNum); 146 } 147 break; 148 } 149 case SVGTokenCy: 150 { 151 SvgNumber aNum; 152 153 if(readSingleNumber(aContent, aNum)) 154 { 155 setCy(aNum); 156 } 157 break; 158 } 159 case SVGTokenFx: 160 { 161 SvgNumber aNum; 162 163 if(readSingleNumber(aContent, aNum)) 164 { 165 setFx(aNum); 166 } 167 break; 168 } 169 case SVGTokenFy: 170 { 171 SvgNumber aNum; 172 173 if(readSingleNumber(aContent, aNum)) 174 { 175 setFy(aNum); 176 } 177 break; 178 } 179 case SVGTokenR: 180 { 181 SvgNumber aNum; 182 183 if(readSingleNumber(aContent, aNum)) 184 { 185 if(aNum.isPositive()) 186 { 187 setR(aNum); 188 } 189 } 190 break; 191 } 192 case SVGTokenGradientUnits: 193 { 194 if(aContent.getLength()) 195 { 196 if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) 197 { 198 setGradientUnits(userSpaceOnUse); 199 } 200 else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) 201 { 202 setGradientUnits(objectBoundingBox); 203 } 204 } 205 break; 206 } 207 case SVGTokenSpreadMethod: 208 { 209 if(aContent.getLength()) 210 { 211 static rtl::OUString aStrPad(rtl::OUString::createFromAscii("pad")); 212 static rtl::OUString aStrReflect(rtl::OUString::createFromAscii("reflect")); 213 static rtl::OUString aStrRepeat(rtl::OUString::createFromAscii("repeat")); 214 215 if(aContent.match(aStrPad, 0)) 216 { 217 setSpreadMethod(drawinglayer::primitive2d::Spread_pad); 218 } 219 else if(aContent.match(aStrReflect, 0)) 220 { 221 setSpreadMethod(drawinglayer::primitive2d::Spread_reflect); 222 } 223 else if(aContent.match(aStrRepeat, 0)) 224 { 225 setSpreadMethod(drawinglayer::primitive2d::Spread_repeat); 226 } 227 } 228 break; 229 } 230 case SVGTokenGradientTransform: 231 { 232 const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); 233 234 if(!aMatrix.isIdentity()) 235 { 236 setGradientTransform(&aMatrix); 237 } 238 break; 239 } 240 case SVGTokenXlinkHref: 241 { 242 const sal_Int32 nLen(aContent.getLength()); 243 244 if(nLen && sal_Unicode('#') == aContent[0]) 245 { 246 maXLink = aContent.copy(1); 247 tryToFindLink(); 248 } 249 break; 250 } 251 default: 252 { 253 break; 254 } 255 } 256 } 257 258 void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const 259 { 260 if(getChildren().empty()) 261 { 262 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 263 264 if(mpXLink) 265 { 266 mpXLink->collectGradientEntries(aVector); 267 } 268 } 269 else 270 { 271 const sal_uInt32 nCount(getChildren().size()); 272 273 for(sal_uInt32 a(0); a < nCount; a++) 274 { 275 const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a]); 276 277 if(pCandidate) 278 { 279 const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes(); 280 281 if(pStyle) 282 { 283 const SvgNumber aOffset(pCandidate->getOffset()); 284 double fOffset(0.0); 285 286 if(Unit_percent == aOffset.getUnit()) 287 { 288 // percent is not relative to distances in ColorStop context, solve locally 289 fOffset = aOffset.getNumber() * 0.01; 290 } 291 else 292 { 293 fOffset = aOffset.solve(*this); 294 } 295 296 if(fOffset < 0.0) 297 { 298 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)"); 299 fOffset = 0.0; 300 } 301 else if(fOffset > 1.0) 302 { 303 OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)"); 304 fOffset = 1.0; 305 } 306 307 aVector.push_back( 308 drawinglayer::primitive2d::SvgGradientEntry( 309 fOffset, 310 pStyle->getStopColor(), 311 pStyle->getStopOpacity().solve(*this))); 312 } 313 else 314 { 315 OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)"); 316 } 317 } 318 } 319 } 320 } 321 322 const SvgNumber SvgGradientNode::getX1() const 323 { 324 if(maX1.isSet()) 325 { 326 return maX1; 327 } 328 329 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 330 331 if(mpXLink) 332 { 333 return mpXLink->getX1(); 334 } 335 336 // default is 0% 337 return SvgNumber(0.0, Unit_percent); 338 } 339 340 const SvgNumber SvgGradientNode::getY1() const 341 { 342 if(maY1.isSet()) 343 { 344 return maY1; 345 } 346 347 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 348 349 if(mpXLink) 350 { 351 return mpXLink->getY1(); 352 } 353 354 // default is 0% 355 return SvgNumber(0.0, Unit_percent); 356 } 357 358 const SvgNumber SvgGradientNode::getX2() const 359 { 360 if(maX2.isSet()) 361 { 362 return maX2; 363 } 364 365 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 366 367 if(mpXLink) 368 { 369 return mpXLink->getX2(); 370 } 371 372 // default is 100% 373 return SvgNumber(100.0, Unit_percent); 374 } 375 376 const SvgNumber SvgGradientNode::getY2() const 377 { 378 if(maY2.isSet()) 379 { 380 return maY2; 381 } 382 383 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 384 385 if(mpXLink) 386 { 387 return mpXLink->getY2(); 388 } 389 390 // default is 0% 391 return SvgNumber(0.0, Unit_percent); 392 } 393 394 const SvgNumber SvgGradientNode::getCx() const 395 { 396 if(maCx.isSet()) 397 { 398 return maCx; 399 } 400 401 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 402 403 if(mpXLink) 404 { 405 return mpXLink->getCx(); 406 } 407 408 // default is 50% 409 return SvgNumber(50.0, Unit_percent); 410 } 411 412 const SvgNumber SvgGradientNode::getCy() const 413 { 414 if(maCy.isSet()) 415 { 416 return maCy; 417 } 418 419 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 420 421 if(mpXLink) 422 { 423 return mpXLink->getCy(); 424 } 425 426 // default is 50% 427 return SvgNumber(50.0, Unit_percent); 428 } 429 430 const SvgNumber SvgGradientNode::getR() const 431 { 432 if(maR.isSet()) 433 { 434 return maR; 435 } 436 437 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 438 439 if(mpXLink) 440 { 441 return mpXLink->getR(); 442 } 443 444 // default is 50% 445 return SvgNumber(50.0, Unit_percent); 446 } 447 448 const SvgNumber* SvgGradientNode::getFx() const 449 { 450 if(maFx.isSet()) 451 { 452 return &maFx; 453 } 454 455 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 456 457 if(mpXLink) 458 { 459 return mpXLink->getFx(); 460 } 461 462 return 0; 463 } 464 465 const SvgNumber* SvgGradientNode::getFy() const 466 { 467 if(maFy.isSet()) 468 { 469 return &maFy; 470 } 471 472 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 473 474 if(mpXLink) 475 { 476 return mpXLink->getFy(); 477 } 478 479 return 0; 480 } 481 482 const basegfx::B2DHomMatrix* SvgGradientNode::getGradientTransform() const 483 { 484 if(mpaGradientTransform) 485 { 486 return mpaGradientTransform; 487 } 488 489 const_cast< SvgGradientNode* >(this)->tryToFindLink(); 490 491 if(mpXLink) 492 { 493 return mpXLink->getGradientTransform(); 494 } 495 496 return 0; 497 } 498 499 void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix* pMatrix) 500 { 501 if(mpaGradientTransform) 502 { 503 delete mpaGradientTransform; 504 mpaGradientTransform = 0; 505 } 506 507 if(pMatrix) 508 { 509 mpaGradientTransform = new basegfx::B2DHomMatrix(*pMatrix); 510 } 511 } 512 513 } // end of namespace svgreader 514 } // end of namespace svgio 515 516 ////////////////////////////////////////////////////////////////////////////// 517 // eof 518