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/svgnode.hxx> 26 #include <basegfx/polygon/b2dpolypolygontools.hxx> 27 #include <svgio/svgreader/svgdocument.hxx> 28 #include <svgio/svgreader/svgnode.hxx> 29 #include <svgio/svgreader/svgstyleattributes.hxx> 30 #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx> 31 #include <tools/urlobj.hxx> 32 33 ////////////////////////////////////////////////////////////////////////////// 34 35 namespace svgio 36 { 37 namespace svgreader 38 { 39 const SvgStyleAttributes* SvgNode::getSvgStyleAttributes() const 40 { 41 return 0; 42 } 43 44 const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const 45 { 46 if(maCssStyleVector.empty()) // #120435# Evaluate for CSS styles only once, this cannot change 47 { 48 const SvgDocument& rDocument = getDocument(); 49 50 if(rDocument.hasSvgStyleAttributesById()) 51 { 52 if(getClass()) 53 { 54 // find all referenced CSS styles, a list of entries is allowed 55 const rtl::OUString* pClassList = getClass(); 56 const sal_Int32 nLen(pClassList->getLength()); 57 sal_Int32 nPos(0); 58 const SvgStyleAttributes* pNew = 0; 59 60 skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); 61 62 while(nPos < nLen) 63 { 64 rtl::OUStringBuffer aTokenValue; 65 66 copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen); 67 skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); 68 69 rtl::OUString aId(rtl::OUString::createFromAscii(".")); 70 const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear()); 71 72 // look for CSS style common to token 73 aId = aId + aOUTokenValue; 74 pNew = rDocument.findSvgStyleAttributesById(aId); 75 76 if(!pNew && rClassStr.getLength()) 77 { 78 // look for CSS style common to class.token 79 aId = rClassStr + aId; 80 81 pNew = rDocument.findSvgStyleAttributesById(aId); 82 } 83 84 if(pNew) 85 { 86 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 87 } 88 } 89 } 90 91 if(maCssStyleVector.empty() && getId()) 92 { 93 // if none found, search for CSS style equal to Id 94 const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId()); 95 96 if(pNew) 97 { 98 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 99 } 100 } 101 102 if(maCssStyleVector.empty() && rClassStr.getLength()) 103 { 104 // if none found, search for CSS style equal to class type 105 const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr); 106 107 if(pNew) 108 { 109 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 110 } 111 } 112 } 113 } 114 115 if(maCssStyleVector.empty()) 116 { 117 return &rOriginal; 118 } 119 else 120 { 121 // set CssStyleParent at maCssStyleVector members to hang them in front of 122 // the existing style. Build a style chain, reset parent of original for security. 123 // Repeated style requests should only be issued from sub-Text nodes and I'm not 124 // sure if in-between text nodes may build other chains (should not happen). But 125 // it's only a re-chaining with pointers (cheap), so allow to do it every time. 126 SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal); 127 pCurrent->setCssStyleParent(0); 128 129 for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++) 130 { 131 SvgStyleAttributes* pCandidate = const_cast< SvgStyleAttributes* >(maCssStyleVector[maCssStyleVector.size() - a - 1]); 132 133 pCandidate->setCssStyleParent(pCurrent); 134 pCurrent = pCandidate; 135 } 136 137 return pCurrent; 138 } 139 } 140 141 SvgNode::SvgNode( 142 SVGToken aType, 143 SvgDocument& rDocument, 144 SvgNode* pParent) 145 : maType(aType), 146 mrDocument(rDocument), 147 mpParent(pParent), 148 mpAlternativeParent(0), 149 maChildren(), 150 mpId(0), 151 mpClass(0), 152 maXmlSpace(XmlSpace_notset), 153 maDisplay(Display_inline), 154 maCssStyleVector() 155 { 156 OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)"); 157 158 if(pParent) 159 { 160 pParent->maChildren.push_back(this); 161 } 162 else 163 { 164 #ifdef DBG_UTIL 165 if(SVGTokenSvg != getType()) 166 { 167 OSL_ENSURE(false, "No parent for this node (!)"); 168 } 169 #endif 170 } 171 } 172 173 SvgNode::~SvgNode() 174 { 175 while(maChildren.size()) 176 { 177 delete maChildren[maChildren.size() - 1]; 178 maChildren.pop_back(); 179 } 180 181 if(mpId) delete mpId; 182 if(mpClass) delete mpClass; 183 } 184 185 void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs) 186 { 187 const sal_uInt32 nAttributes(xAttribs->getLength()); 188 189 for(sal_uInt32 a(0); a < nAttributes; a++) 190 { 191 const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a)); 192 193 parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a)); 194 } 195 } 196 197 void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) 198 { 199 switch(aSVGToken) 200 { 201 case SVGTokenId: 202 { 203 if(aContent.getLength()) 204 { 205 setId(&aContent); 206 } 207 break; 208 } 209 case SVGTokenClass: 210 { 211 if(aContent.getLength()) 212 { 213 setClass(&aContent); 214 } 215 break; 216 } 217 case SVGTokenXmlSpace: 218 { 219 if(aContent.getLength()) 220 { 221 static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default")); 222 static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve")); 223 224 if(aContent.match(aStrDefault)) 225 { 226 setXmlSpace(XmlSpace_default); 227 } 228 else if(aContent.match(aStrPreserve)) 229 { 230 setXmlSpace(XmlSpace_preserve); 231 } 232 } 233 break; 234 } 235 case SVGTokenDisplay: 236 { 237 if(aContent.getLength()) 238 { 239 static rtl::OUString aStrInline(rtl::OUString::createFromAscii("inline")); 240 static rtl::OUString aStrBlock(rtl::OUString::createFromAscii("block")); 241 static rtl::OUString aStrList_item(rtl::OUString::createFromAscii("list-item")); 242 static rtl::OUString aStrRun_in(rtl::OUString::createFromAscii("run-in")); 243 static rtl::OUString aStrCompact(rtl::OUString::createFromAscii("compact")); 244 static rtl::OUString aStrMarker(rtl::OUString::createFromAscii("marker")); 245 static rtl::OUString aStrTable(rtl::OUString::createFromAscii("table")); 246 static rtl::OUString aStrInline_table(rtl::OUString::createFromAscii("inline-table")); 247 static rtl::OUString aStrTable_row_group(rtl::OUString::createFromAscii("table-row-group")); 248 static rtl::OUString aStrTable_header_group(rtl::OUString::createFromAscii("table-header-group")); 249 static rtl::OUString aStrTable_footer_group(rtl::OUString::createFromAscii("table-footer-group")); 250 static rtl::OUString aStrTable_row(rtl::OUString::createFromAscii("table-row")); 251 static rtl::OUString aStrTable_column_group(rtl::OUString::createFromAscii("table-column-group")); 252 static rtl::OUString aStrTable_column(rtl::OUString::createFromAscii("table-column")); 253 static rtl::OUString aStrTable_cell(rtl::OUString::createFromAscii("table-cell")); 254 static rtl::OUString aStrTable_caption(rtl::OUString::createFromAscii("table-caption")); 255 static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none")); 256 static rtl::OUString aStrInherit(rtl::OUString::createFromAscii("inherit")); 257 258 if(aContent.match(aStrInline)) 259 { 260 setDisplay(Display_inline); 261 } 262 else if(aContent.match(aStrNone)) 263 { 264 setDisplay(Display_none); 265 } 266 else if(aContent.match(aStrInherit)) 267 { 268 setDisplay(Display_inherit); 269 } 270 else if(aContent.match(aStrBlock)) 271 { 272 setDisplay(Display_block); 273 } 274 else if(aContent.match(aStrList_item)) 275 { 276 setDisplay(Display_list_item); 277 } 278 else if(aContent.match(aStrRun_in)) 279 { 280 setDisplay(Display_run_in); 281 } 282 else if(aContent.match(aStrCompact)) 283 { 284 setDisplay(Display_compact); 285 } 286 else if(aContent.match(aStrMarker)) 287 { 288 setDisplay(Display_marker); 289 } 290 else if(aContent.match(aStrTable)) 291 { 292 setDisplay(Display_table); 293 } 294 else if(aContent.match(aStrInline_table)) 295 { 296 setDisplay(Display_inline_table); 297 } 298 else if(aContent.match(aStrTable_row_group)) 299 { 300 setDisplay(Display_table_row_group); 301 } 302 else if(aContent.match(aStrTable_header_group)) 303 { 304 setDisplay(Display_table_header_group); 305 } 306 else if(aContent.match(aStrTable_footer_group)) 307 { 308 setDisplay(Display_table_footer_group); 309 } 310 else if(aContent.match(aStrTable_row)) 311 { 312 setDisplay(Display_table_row); 313 } 314 else if(aContent.match(aStrTable_column_group)) 315 { 316 setDisplay(Display_table_column_group); 317 } 318 else if(aContent.match(aStrTable_column)) 319 { 320 setDisplay(Display_table_column); 321 } 322 else if(aContent.match(aStrTable_cell)) 323 { 324 setDisplay(Display_table_cell); 325 } 326 else if(aContent.match(aStrTable_caption)) 327 { 328 setDisplay(Display_table_caption); 329 } 330 } 331 break; 332 } 333 default: 334 { 335 break; 336 } 337 } 338 } 339 340 void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 341 { 342 if(Display_none == getDisplay()) 343 { 344 return; 345 } 346 347 if(!bReferenced) 348 { 349 if(SVGTokenDefs == getType() || 350 SVGTokenSymbol == getType() || 351 SVGTokenClipPathNode == getType() || 352 SVGTokenMask == getType() || 353 SVGTokenMarker == getType() || 354 SVGTokenPattern == getType()) 355 { 356 // do not decompose defs or symbol nodes (these hold only style-like 357 // objects which may be used by referencing them) except when doing 358 // so controlled referenced 359 360 // also do not decompose ClipPaths and Masks. These should be embedded 361 // in a defs node (which gets not decomposed by itself), but you never 362 // know 363 364 // also not directly used are Markers and Patterns, only indirecty used 365 // by reference 366 367 // #121656# also do not decompose nodes which have display="none" set 368 // as property 369 return; 370 } 371 } 372 373 const SvgNodeVector& rChildren = getChildren(); 374 375 if(!rChildren.empty()) 376 { 377 const sal_uInt32 nCount(rChildren.size()); 378 379 for(sal_uInt32 a(0); a < nCount; a++) 380 { 381 SvgNode* pCandidate = rChildren[a]; 382 383 if(pCandidate && Display_none != pCandidate->getDisplay()) 384 { 385 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 386 387 pCandidate->decomposeSvgNode(aNewTarget, bReferenced); 388 389 if(aNewTarget.hasElements()) 390 { 391 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); 392 } 393 } 394 else 395 { 396 OSL_ENSURE(false, "Null-Pointer in child node list (!)"); 397 } 398 } 399 400 if(rTarget.hasElements()) 401 { 402 const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); 403 404 if(pStyles) 405 { 406 // check if we have Title or Desc 407 const rtl::OUString& rTitle = pStyles->getTitle(); 408 const rtl::OUString& rDesc = pStyles->getDesc(); 409 410 if(rTitle.getLength() || rDesc.getLength()) 411 { 412 // default object name is empty 413 rtl::OUString aObjectName; 414 415 // use path as object name when outmost element 416 if(SVGTokenSvg == getType()) 417 { 418 aObjectName = getDocument().getAbsolutePath(); 419 420 if(aObjectName.getLength()) 421 { 422 INetURLObject aURL(aObjectName); 423 424 aObjectName = aURL.getName( 425 INetURLObject::LAST_SEGMENT, 426 true, 427 INetURLObject::DECODE_WITH_CHARSET); 428 } 429 } 430 431 // pack in ObjectInfoPrimitive2D group 432 const drawinglayer::primitive2d::Primitive2DReference xRef( 433 new drawinglayer::primitive2d::ObjectInfoPrimitive2D( 434 rTarget, 435 aObjectName, 436 rTitle, 437 rDesc)); 438 439 rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 440 } 441 } 442 } 443 } 444 } 445 446 const basegfx::B2DRange* SvgNode::getCurrentViewPort() const 447 { 448 if(getParent()) 449 { 450 return getParent()->getCurrentViewPort(); 451 } 452 else 453 { 454 return 0; 455 } 456 } 457 458 double SvgNode::getCurrentFontSize() const 459 { 460 if(getSvgStyleAttributes()) 461 { 462 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate); 463 } 464 else if(getParent()) 465 { 466 return getParent()->getCurrentFontSize(); 467 } 468 else 469 { 470 return 0.0; 471 } 472 } 473 474 double SvgNode::getCurrentXHeight() const 475 { 476 if(getSvgStyleAttributes()) 477 { 478 // for XHeight, use FontSize currently 479 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate); 480 } 481 else if(getParent()) 482 { 483 return getParent()->getCurrentXHeight(); 484 } 485 else 486 { 487 return 0.0; 488 } 489 } 490 491 void SvgNode::setId(const rtl::OUString* pfId) 492 { 493 if(mpId) 494 { 495 mrDocument.removeSvgNodeFromMapper(*mpId); 496 delete mpId; 497 mpId = 0; 498 } 499 500 if(pfId) 501 { 502 mpId = new rtl::OUString(*pfId); 503 mrDocument.addSvgNodeToMapper(*mpId, *this); 504 } 505 } 506 507 void SvgNode::setClass(const rtl::OUString* pfClass) 508 { 509 if(mpClass) 510 { 511 mrDocument.removeSvgNodeFromMapper(*mpClass); 512 delete mpClass; 513 mpClass = 0; 514 } 515 516 if(pfClass) 517 { 518 mpClass = new rtl::OUString(*pfClass); 519 mrDocument.addSvgNodeToMapper(*mpClass, *this); 520 } 521 } 522 523 XmlSpace SvgNode::getXmlSpace() const 524 { 525 if(maXmlSpace != XmlSpace_notset) 526 { 527 return maXmlSpace; 528 } 529 530 if(getParent()) 531 { 532 return getParent()->getXmlSpace(); 533 } 534 535 // default is XmlSpace_default 536 return XmlSpace_default; 537 } 538 539 } // end of namespace svgreader 540 } // end of namespace svgio 541 542 ////////////////////////////////////////////////////////////////////////////// 543 // eof 544