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 const SvgDocument& rDocument = getDocument(); 47 48 if(rDocument.hasSvgStyleAttributesById()) 49 { 50 if(getClass()) 51 { 52 // find all referenced CSS styles, a list of entries is allowed 53 const rtl::OUString* pClassList = getClass(); 54 const sal_Int32 nLen(pClassList->getLength()); 55 sal_Int32 nPos(0); 56 const SvgStyleAttributes* pNew = 0; 57 58 skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); 59 60 while(nPos < nLen) 61 { 62 rtl::OUStringBuffer aTokenValue; 63 64 copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen); 65 skip_char(*pClassList, sal_Unicode(' '), nPos, nLen); 66 67 rtl::OUString aId(rtl::OUString::createFromAscii(".")); 68 const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear()); 69 70 // look for CSS style common to token 71 aId = aId + aOUTokenValue; 72 pNew = rDocument.findSvgStyleAttributesById(aId); 73 74 if(!pNew && rClassStr.getLength()) 75 { 76 // look for CSS style common to class.token 77 aId = rClassStr + aId; 78 79 pNew = rDocument.findSvgStyleAttributesById(aId); 80 } 81 82 if(pNew) 83 { 84 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 85 } 86 } 87 } 88 89 if(maCssStyleVector.empty() && getId()) 90 { 91 // if none found, search for CSS style equal to Id 92 const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId()); 93 94 if(pNew) 95 { 96 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 97 } 98 } 99 100 if(maCssStyleVector.empty() && rClassStr.getLength()) 101 { 102 // if none found, search for CSS style equal to class type 103 const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr); 104 105 if(pNew) 106 { 107 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew); 108 } 109 } 110 } 111 112 if(maCssStyleVector.empty()) 113 { 114 return &rOriginal; 115 } 116 else 117 { 118 // set CssStyleParent at maCssStyleVector members to hang them in front of 119 // the existing style 120 SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal); 121 122 for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++) 123 { 124 SvgStyleAttributes* pCandidate = const_cast< SvgStyleAttributes* >(maCssStyleVector[maCssStyleVector.size() - a - 1]); 125 126 pCandidate->setCssStyleParent(pCurrent); 127 pCurrent = pCandidate; 128 } 129 130 return pCurrent; 131 } 132 } 133 134 SvgNode::SvgNode( 135 SVGToken aType, 136 SvgDocument& rDocument, 137 SvgNode* pParent) 138 : maType(aType), 139 mrDocument(rDocument), 140 mpParent(pParent), 141 mpAlternativeParent(0), 142 maChildren(), 143 mpId(0), 144 mpClass(0), 145 maXmlSpace(XmlSpace_notset), 146 maCssStyleVector() 147 { 148 OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)"); 149 150 if(pParent) 151 { 152 pParent->maChildren.push_back(this); 153 } 154 else 155 { 156 #ifdef DBG_UTIL 157 if(SVGTokenSvg != getType()) 158 { 159 OSL_ENSURE(false, "No parent for this node (!)"); 160 } 161 #endif 162 } 163 } 164 165 SvgNode::~SvgNode() 166 { 167 while(maChildren.size()) 168 { 169 delete maChildren[maChildren.size() - 1]; 170 maChildren.pop_back(); 171 } 172 173 if(mpId) delete mpId; 174 if(mpClass) delete mpClass; 175 } 176 177 void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs) 178 { 179 const sal_uInt32 nAttributes(xAttribs->getLength()); 180 181 for(sal_uInt32 a(0); a < nAttributes; a++) 182 { 183 const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a)); 184 185 parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a)); 186 } 187 } 188 189 void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) 190 { 191 switch(aSVGToken) 192 { 193 case SVGTokenId: 194 { 195 if(aContent.getLength()) 196 { 197 setId(&aContent); 198 } 199 break; 200 } 201 case SVGTokenClass: 202 { 203 if(aContent.getLength()) 204 { 205 setClass(&aContent); 206 } 207 break; 208 } 209 case SVGTokenXmlSpace: 210 { 211 if(aContent.getLength()) 212 { 213 static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default")); 214 static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve")); 215 216 if(aContent.match(aStrDefault)) 217 { 218 setXmlSpace(XmlSpace_default); 219 } 220 else if(aContent.match(aStrPreserve)) 221 { 222 setXmlSpace(XmlSpace_preserve); 223 } 224 } 225 break; 226 } 227 default: 228 { 229 break; 230 } 231 } 232 } 233 234 void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 235 { 236 if(!bReferenced) 237 { 238 if(SVGTokenDefs == getType() || 239 SVGTokenSymbol == getType() || 240 SVGTokenClipPathNode == getType() || 241 SVGTokenMask == getType() || 242 SVGTokenMarker == getType() || 243 SVGTokenPattern == getType()) 244 { 245 // do not decompose defs or symbol nodes (these hold only style-like 246 // objects which may be used by referencing them) except when doing 247 // so controlled referenced 248 249 // also do not decompose ClipPaths and Masks. These should be embedded 250 // in a defs node (which gets not decomposed by itself), but you never 251 // know 252 253 // also not directly used are Markers and Patterns, only indirecty used 254 // by reference 255 return; 256 } 257 } 258 259 const SvgNodeVector& rChildren = getChildren(); 260 261 if(!rChildren.empty()) 262 { 263 const sal_uInt32 nCount(rChildren.size()); 264 265 for(sal_uInt32 a(0); a < nCount; a++) 266 { 267 SvgNode* pCandidate = rChildren[a]; 268 269 if(pCandidate) 270 { 271 drawinglayer::primitive2d::Primitive2DSequence aNewTarget; 272 273 pCandidate->decomposeSvgNode(aNewTarget, bReferenced); 274 275 if(aNewTarget.hasElements()) 276 { 277 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); 278 } 279 } 280 else 281 { 282 OSL_ENSURE(false, "Null-Pointer in child node list (!)"); 283 } 284 } 285 286 if(rTarget.hasElements()) 287 { 288 const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); 289 290 if(pStyles) 291 { 292 // check if we have Title or Desc 293 const rtl::OUString& rTitle = pStyles->getTitle(); 294 const rtl::OUString& rDesc = pStyles->getDesc(); 295 296 if(rTitle.getLength() || rDesc.getLength()) 297 { 298 // default object name is empty 299 rtl::OUString aObjectName; 300 301 // use path as object name when outmost element 302 if(SVGTokenSvg == getType()) 303 { 304 aObjectName = getDocument().getAbsolutePath(); 305 306 if(aObjectName.getLength()) 307 { 308 INetURLObject aURL(aObjectName); 309 310 aObjectName = aURL.getName( 311 INetURLObject::LAST_SEGMENT, 312 true, 313 INetURLObject::DECODE_WITH_CHARSET); 314 } 315 } 316 317 // pack in ObjectInfoPrimitive2D group 318 const drawinglayer::primitive2d::Primitive2DReference xRef( 319 new drawinglayer::primitive2d::ObjectInfoPrimitive2D( 320 rTarget, 321 aObjectName, 322 rTitle, 323 rDesc)); 324 325 rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 326 } 327 } 328 } 329 } 330 } 331 332 const basegfx::B2DRange* SvgNode::getCurrentViewPort() const 333 { 334 if(getParent()) 335 { 336 return getParent()->getCurrentViewPort(); 337 } 338 else 339 { 340 return 0; 341 } 342 } 343 344 double SvgNode::getCurrentFontSize() const 345 { 346 if(getSvgStyleAttributes()) 347 { 348 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate); 349 } 350 else if(getParent()) 351 { 352 return getParent()->getCurrentFontSize(); 353 } 354 else 355 { 356 return 0.0; 357 } 358 } 359 360 double SvgNode::getCurrentXHeight() const 361 { 362 if(getSvgStyleAttributes()) 363 { 364 // for XHeight, use FontSize currently 365 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate); 366 } 367 else if(getParent()) 368 { 369 return getParent()->getCurrentXHeight(); 370 } 371 else 372 { 373 return 0.0; 374 } 375 } 376 377 void SvgNode::setId(const rtl::OUString* pfId) 378 { 379 if(mpId) 380 { 381 mrDocument.removeSvgNodeFromMapper(*mpId); 382 delete mpId; 383 mpId = 0; 384 } 385 386 if(pfId) 387 { 388 mpId = new rtl::OUString(*pfId); 389 mrDocument.addSvgNodeToMapper(*mpId, *this); 390 } 391 } 392 393 void SvgNode::setClass(const rtl::OUString* pfClass) 394 { 395 if(mpClass) 396 { 397 mrDocument.removeSvgNodeFromMapper(*mpClass); 398 delete mpClass; 399 mpClass = 0; 400 } 401 402 if(pfClass) 403 { 404 mpClass = new rtl::OUString(*pfClass); 405 mrDocument.addSvgNodeToMapper(*mpClass, *this); 406 } 407 } 408 409 XmlSpace SvgNode::getXmlSpace() const 410 { 411 if(maXmlSpace != XmlSpace_notset) 412 { 413 return maXmlSpace; 414 } 415 416 if(getParent()) 417 { 418 return getParent()->getXmlSpace(); 419 } 420 421 // default is XmlSpace_default 422 return XmlSpace_default; 423 } 424 425 } // end of namespace svgreader 426 } // end of namespace svgio 427 428 ////////////////////////////////////////////////////////////////////////////// 429 // eof 430