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/svgdocumenthandler.hxx> 26 #include <svgio/svgreader/svgtoken.hxx> 27 #include <svgio/svgreader/svgsvgnode.hxx> 28 #include <svgio/svgreader/svggnode.hxx> 29 #include <svgio/svgreader/svgnode.hxx> 30 #include <svgio/svgreader/svgpathnode.hxx> 31 #include <svgio/svgreader/svgrectnode.hxx> 32 #include <svgio/svgreader/svggradientnode.hxx> 33 #include <svgio/svgreader/svggradientstopnode.hxx> 34 #include <svgio/svgreader/svgsymbolnode.hxx> 35 #include <svgio/svgreader/svgusenode.hxx> 36 #include <svgio/svgreader/svgcirclenode.hxx> 37 #include <svgio/svgreader/svgellipsenode.hxx> 38 #include <svgio/svgreader/svglinenode.hxx> 39 #include <svgio/svgreader/svgpolynode.hxx> 40 #include <svgio/svgreader/svgsymbolnode.hxx> 41 #include <svgio/svgreader/svgtextnode.hxx> 42 #include <svgio/svgreader/svgcharacternode.hxx> 43 #include <svgio/svgreader/svgtspannode.hxx> 44 #include <svgio/svgreader/svgtrefnode.hxx> 45 #include <svgio/svgreader/svgtextpathnode.hxx> 46 #include <svgio/svgreader/svgstylenode.hxx> 47 #include <svgio/svgreader/svgimagenode.hxx> 48 #include <svgio/svgreader/svgclippathnode.hxx> 49 #include <svgio/svgreader/svgmasknode.hxx> 50 #include <svgio/svgreader/svgmarkernode.hxx> 51 #include <svgio/svgreader/svgpatternnode.hxx> 52 53 ////////////////////////////////////////////////////////////////////////////// 54 55 using namespace com::sun::star; 56 57 ////////////////////////////////////////////////////////////////////////////// 58 59 namespace 60 { 61 svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast) 62 { 63 if(pNode) 64 { 65 const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren(); 66 const sal_uInt32 nCount(rChilds.size()); 67 68 for(sal_uInt32 a(0); a < nCount; a++) 69 { 70 svgio::svgreader::SvgNode* pCandidate = rChilds[a]; 71 72 if(pCandidate) 73 { 74 switch(pCandidate->getType()) 75 { 76 case svgio::svgreader::SVGTokenCharacter: 77 { 78 // clean whitespace in text span 79 svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate); 80 pCharNode->whiteSpaceHandling(); 81 82 // pCharNode may have lost all text. If that's the case, ignore 83 // as invalid character node 84 if(pCharNode->getText().getLength()) 85 { 86 if(pLast) 87 { 88 // add in-between whitespace (single space) to last 89 // known character node 90 pLast->addGap(); 91 } 92 93 // remember new last corected character node 94 pLast = pCharNode; 95 } 96 break; 97 } 98 case svgio::svgreader::SVGTokenTspan: 99 case svgio::svgreader::SVGTokenTextPath: 100 case svgio::svgreader::SVGTokenTref: 101 { 102 // recursively clean whitespaces in subhierarchy 103 pLast = whiteSpaceHandling(pCandidate, pLast); 104 break; 105 } 106 default: 107 { 108 OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)"); 109 break; 110 } 111 } 112 } 113 } 114 } 115 116 return pLast; 117 } 118 } 119 120 ////////////////////////////////////////////////////////////////////////////// 121 122 namespace svgio 123 { 124 namespace svgreader 125 { 126 SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath) 127 : maDocument(aAbsolutePath), 128 mpTarget(0), 129 maCssContents() 130 { 131 } 132 133 SvgDocHdl::~SvgDocHdl() 134 { 135 #ifdef DBG_UTIL 136 if(mpTarget) 137 { 138 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)"); 139 delete mpTarget; 140 } 141 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)"); 142 #endif 143 } 144 145 void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) 146 { 147 OSL_ENSURE(!mpTarget, "Already a target at document start (!)"); 148 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)"); 149 } 150 151 void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) 152 { 153 OSL_ENSURE(!mpTarget, "Still a target at document end (!)"); 154 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)"); 155 } 156 157 void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException) 158 { 159 if(aName.getLength()) 160 { 161 const SVGToken aSVGToken(StrToSVGToken(aName)); 162 163 switch(aSVGToken) 164 { 165 /// structural elements 166 case SVGTokenSymbol: 167 { 168 /// new basic node for Symbol. Content gets scanned, but 169 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) 170 mpTarget = new SvgSymbolNode(maDocument, mpTarget); 171 mpTarget->parseAttributes(xAttribs); 172 break; 173 } 174 case SVGTokenDefs: 175 case SVGTokenG: 176 { 177 /// new node for Defs/G 178 mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); 179 mpTarget->parseAttributes(xAttribs); 180 break; 181 } 182 case SVGTokenSvg: 183 { 184 /// new node for Svg 185 mpTarget = new SvgSvgNode(maDocument, mpTarget); 186 mpTarget->parseAttributes(xAttribs); 187 break; 188 } 189 case SVGTokenUse: 190 { 191 /// new node for Use 192 mpTarget = new SvgUseNode(maDocument, mpTarget); 193 mpTarget->parseAttributes(xAttribs); 194 break; 195 } 196 197 /// shape elements 198 case SVGTokenCircle: 199 { 200 /// new node for Circle 201 mpTarget = new SvgCircleNode(maDocument, mpTarget); 202 mpTarget->parseAttributes(xAttribs); 203 break; 204 } 205 case SVGTokenEllipse: 206 { 207 /// new node for Ellipse 208 mpTarget = new SvgEllipseNode(maDocument, mpTarget); 209 mpTarget->parseAttributes(xAttribs); 210 break; 211 } 212 case SVGTokenLine: 213 { 214 /// new node for Line 215 mpTarget = new SvgLineNode(maDocument, mpTarget); 216 mpTarget->parseAttributes(xAttribs); 217 break; 218 } 219 case SVGTokenPath: 220 { 221 /// new node for Path 222 mpTarget = new SvgPathNode(maDocument, mpTarget); 223 mpTarget->parseAttributes(xAttribs); 224 break; 225 } 226 case SVGTokenPolygon: 227 { 228 /// new node for Polygon 229 mpTarget = new SvgPolyNode(maDocument, mpTarget, false); 230 mpTarget->parseAttributes(xAttribs); 231 break; 232 } 233 case SVGTokenPolyline: 234 { 235 /// new node for Polyline 236 mpTarget = new SvgPolyNode(maDocument, mpTarget, true); 237 mpTarget->parseAttributes(xAttribs); 238 break; 239 } 240 case SVGTokenRect: 241 { 242 /// new node for Rect 243 mpTarget = new SvgRectNode(maDocument, mpTarget); 244 mpTarget->parseAttributes(xAttribs); 245 break; 246 } 247 case SVGTokenImage: 248 { 249 /// new node for Image 250 mpTarget = new SvgImageNode(maDocument, mpTarget); 251 mpTarget->parseAttributes(xAttribs); 252 break; 253 } 254 255 /// gradients 256 case SVGTokenLinearGradient: 257 case SVGTokenRadialGradient: 258 { 259 mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); 260 mpTarget->parseAttributes(xAttribs); 261 break; 262 } 263 264 /// gradient stops 265 case SVGTokenStop: 266 { 267 mpTarget = new SvgGradientStopNode(maDocument, mpTarget); 268 mpTarget->parseAttributes(xAttribs); 269 break; 270 } 271 272 /// text 273 case SVGTokenText: 274 { 275 mpTarget = new SvgTextNode(maDocument, mpTarget); 276 mpTarget->parseAttributes(xAttribs); 277 break; 278 } 279 case SVGTokenTspan: 280 { 281 mpTarget = new SvgTspanNode(maDocument, mpTarget); 282 mpTarget->parseAttributes(xAttribs); 283 break; 284 } 285 case SVGTokenTref: 286 { 287 mpTarget = new SvgTrefNode(maDocument, mpTarget); 288 mpTarget->parseAttributes(xAttribs); 289 break; 290 } 291 case SVGTokenTextPath: 292 { 293 mpTarget = new SvgTextPathNode(maDocument, mpTarget); 294 mpTarget->parseAttributes(xAttribs); 295 break; 296 } 297 298 /// styles (as stylesheets) 299 case SVGTokenStyle: 300 { 301 SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget); 302 mpTarget = pNew; 303 mpTarget->parseAttributes(xAttribs); 304 305 if(pNew->isTextCss()) 306 { 307 maCssContents.push_back(rtl::OUString()); 308 } 309 break; 310 } 311 312 /// structural elements clip-path and mask. Content gets scanned, but 313 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) 314 case SVGTokenClipPathNode: 315 { 316 /// new node for ClipPath 317 mpTarget = new SvgClipPathNode(maDocument, mpTarget); 318 mpTarget->parseAttributes(xAttribs); 319 break; 320 } 321 case SVGTokenMask: 322 { 323 /// new node for Mask 324 mpTarget = new SvgMaskNode(maDocument, mpTarget); 325 mpTarget->parseAttributes(xAttribs); 326 break; 327 } 328 329 /// structural element marker 330 case SVGTokenMarker: 331 { 332 /// new node for marker 333 mpTarget = new SvgMarkerNode(maDocument, mpTarget); 334 mpTarget->parseAttributes(xAttribs); 335 break; 336 } 337 338 /// structural element pattern 339 case SVGTokenPattern: 340 { 341 /// new node for pattern 342 mpTarget = new SvgPatternNode(maDocument, mpTarget); 343 mpTarget->parseAttributes(xAttribs); 344 break; 345 } 346 347 default: 348 { 349 /// invalid token, ignore 350 #ifdef DBG_UTIL 351 myAssert( 352 rtl::OUString::createFromAscii("Unknown Base SvgToken <") + 353 aName + 354 rtl::OUString::createFromAscii("> (!)")); 355 #endif 356 break; 357 } 358 } 359 } 360 } 361 362 void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException) 363 { 364 if(aName.getLength()) 365 { 366 const SVGToken aSVGToken(StrToSVGToken(aName)); 367 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0); 368 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0); 369 370 switch(aSVGToken) 371 { 372 /// valid tokens for which a new one was created 373 374 /// structural elements 375 case SVGTokenDefs: 376 case SVGTokenG: 377 case SVGTokenSvg: 378 case SVGTokenSymbol: 379 case SVGTokenUse: 380 381 /// shape elements 382 case SVGTokenCircle: 383 case SVGTokenEllipse: 384 case SVGTokenLine: 385 case SVGTokenPath: 386 case SVGTokenPolygon: 387 case SVGTokenPolyline: 388 case SVGTokenRect: 389 case SVGTokenImage: 390 391 /// gradients 392 case SVGTokenLinearGradient: 393 case SVGTokenRadialGradient: 394 395 /// gradient stops 396 case SVGTokenStop: 397 398 /// text 399 case SVGTokenText: 400 case SVGTokenTspan: 401 case SVGTokenTextPath: 402 case SVGTokenTref: 403 404 /// styles (as stylesheets) 405 case SVGTokenStyle: 406 407 /// structural elements clip-path and mask 408 case SVGTokenClipPathNode: 409 case SVGTokenMask: 410 411 /// structural element marker 412 case SVGTokenMarker: 413 414 /// structural element pattern 415 case SVGTokenPattern: 416 417 /// content handling after parsing 418 { 419 if(mpTarget) 420 { 421 if(!mpTarget->getParent()) 422 { 423 // last element closing, save this tree 424 maDocument.appendNode(mpTarget); 425 } 426 427 mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); 428 } 429 else 430 { 431 OSL_ENSURE(false, "Closing token, but no context (!)"); 432 } 433 break; 434 } 435 default: 436 { 437 /// invalid token, ignore 438 } 439 } 440 441 if(pCssStyle && pCssStyle->isTextCss()) 442 { 443 // css style parsing 444 if(maCssContents.size()) 445 { 446 // need to interpret css styles and remember them as StyleSheets 447 pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1)); 448 maCssContents.pop_back(); 449 } 450 else 451 { 452 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); 453 } 454 } 455 456 if(pWhitespaceCheck) 457 { 458 // cleanup read strings 459 whiteSpaceHandling(pWhitespaceCheck, 0); 460 } 461 } 462 } 463 464 void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException) 465 { 466 if(mpTarget) 467 { 468 const sal_uInt32 nLength(aChars.getLength()); 469 470 if(nLength && 471 (SVGTokenText == mpTarget->getType() || 472 SVGTokenTspan == mpTarget->getType() || 473 SVGTokenTextPath == mpTarget->getType() || 474 SVGTokenStyle == mpTarget->getType())) 475 { 476 switch(mpTarget->getType()) 477 { 478 case SVGTokenText: 479 case SVGTokenTspan: 480 case SVGTokenTextPath: 481 { 482 const SvgNodeVector& rChilds = mpTarget->getChildren(); 483 SvgCharacterNode* pTarget = 0; 484 485 if(rChilds.size()) 486 { 487 pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]); 488 } 489 490 if(pTarget) 491 { 492 // concatenate to current character span 493 pTarget->concatenate(aChars); 494 } 495 else 496 { 497 // add character span as simplified tspan (no arguments) 498 // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode 499 new SvgCharacterNode(maDocument, mpTarget, aChars); 500 } 501 break; 502 } 503 case SVGTokenStyle: 504 { 505 SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); 506 507 if(rSvgStyleNode.isTextCss()) 508 { 509 // collect characters for css style 510 if(maCssContents.size()) 511 { 512 const ::rtl::OUString aTrimmedChars(aChars.trim()); 513 514 if(aTrimmedChars.getLength()) 515 { 516 std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1); 517 (*aString) += aTrimmedChars; 518 } 519 } 520 else 521 { 522 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); 523 } 524 } 525 break; 526 } 527 default: 528 { 529 // characters not used by a known node 530 break; 531 } 532 } 533 } 534 } 535 } 536 537 void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException) 538 { 539 } 540 541 void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException) 542 { 543 } 544 545 void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException) 546 { 547 } 548 } // end of namespace svgreader 549 } // end of namespace svgio 550 551 ////////////////////////////////////////////////////////////////////////////// 552 // eof 553