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 { 130 } 131 132 SvgDocHdl::~SvgDocHdl() 133 { 134 #ifdef DBG_UTIL 135 if(mpTarget) 136 { 137 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)"); 138 delete mpTarget; 139 } 140 #endif 141 } 142 143 void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) 144 { 145 OSL_ENSURE(!mpTarget, "Already a target at document start (!)"); 146 } 147 148 void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) 149 { 150 OSL_ENSURE(!mpTarget, "Still a target at document end (!)"); 151 } 152 153 void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException) 154 { 155 if(aName.getLength()) 156 { 157 const SVGToken aSVGToken(StrToSVGToken(aName)); 158 159 switch(aSVGToken) 160 { 161 /// structural elements 162 case SVGTokenSymbol: 163 { 164 /// new basic node for Symbol. Content gets scanned, but 165 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) 166 mpTarget = new SvgSymbolNode(maDocument, mpTarget); 167 mpTarget->parseAttributes(xAttribs); 168 break; 169 } 170 case SVGTokenDefs: 171 case SVGTokenG: 172 { 173 /// new node for Defs/G 174 mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); 175 mpTarget->parseAttributes(xAttribs); 176 break; 177 } 178 case SVGTokenSvg: 179 { 180 /// new node for Svg 181 mpTarget = new SvgSvgNode(maDocument, mpTarget); 182 mpTarget->parseAttributes(xAttribs); 183 break; 184 } 185 case SVGTokenUse: 186 { 187 /// new node for Use 188 mpTarget = new SvgUseNode(maDocument, mpTarget); 189 mpTarget->parseAttributes(xAttribs); 190 break; 191 } 192 193 /// shape elements 194 case SVGTokenCircle: 195 { 196 /// new node for Circle 197 mpTarget = new SvgCircleNode(maDocument, mpTarget); 198 mpTarget->parseAttributes(xAttribs); 199 break; 200 } 201 case SVGTokenEllipse: 202 { 203 /// new node for Ellipse 204 mpTarget = new SvgEllipseNode(maDocument, mpTarget); 205 mpTarget->parseAttributes(xAttribs); 206 break; 207 } 208 case SVGTokenLine: 209 { 210 /// new node for Line 211 mpTarget = new SvgLineNode(maDocument, mpTarget); 212 mpTarget->parseAttributes(xAttribs); 213 break; 214 } 215 case SVGTokenPath: 216 { 217 /// new node for Path 218 mpTarget = new SvgPathNode(maDocument, mpTarget); 219 mpTarget->parseAttributes(xAttribs); 220 break; 221 } 222 case SVGTokenPolygon: 223 { 224 /// new node for Polygon 225 mpTarget = new SvgPolyNode(maDocument, mpTarget, false); 226 mpTarget->parseAttributes(xAttribs); 227 break; 228 } 229 case SVGTokenPolyline: 230 { 231 /// new node for Polyline 232 mpTarget = new SvgPolyNode(maDocument, mpTarget, true); 233 mpTarget->parseAttributes(xAttribs); 234 break; 235 } 236 case SVGTokenRect: 237 { 238 /// new node for Rect 239 mpTarget = new SvgRectNode(maDocument, mpTarget); 240 mpTarget->parseAttributes(xAttribs); 241 break; 242 } 243 case SVGTokenImage: 244 { 245 /// new node for Image 246 mpTarget = new SvgImageNode(maDocument, mpTarget); 247 mpTarget->parseAttributes(xAttribs); 248 break; 249 } 250 251 /// gradients 252 case SVGTokenLinearGradient: 253 case SVGTokenRadialGradient: 254 { 255 mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); 256 mpTarget->parseAttributes(xAttribs); 257 break; 258 } 259 260 /// gradient stops 261 case SVGTokenStop: 262 { 263 mpTarget = new SvgGradientStopNode(maDocument, mpTarget); 264 mpTarget->parseAttributes(xAttribs); 265 break; 266 } 267 268 /// text 269 case SVGTokenText: 270 { 271 mpTarget = new SvgTextNode(maDocument, mpTarget); 272 mpTarget->parseAttributes(xAttribs); 273 break; 274 } 275 case SVGTokenTspan: 276 { 277 mpTarget = new SvgTspanNode(maDocument, mpTarget); 278 mpTarget->parseAttributes(xAttribs); 279 break; 280 } 281 case SVGTokenTref: 282 { 283 mpTarget = new SvgTrefNode(maDocument, mpTarget); 284 mpTarget->parseAttributes(xAttribs); 285 break; 286 } 287 case SVGTokenTextPath: 288 { 289 mpTarget = new SvgTextPathNode(maDocument, mpTarget); 290 mpTarget->parseAttributes(xAttribs); 291 break; 292 } 293 294 /// styles (as stylesheets) 295 case SVGTokenStyle: 296 { 297 mpTarget = new SvgStyleNode(maDocument, mpTarget); 298 mpTarget->parseAttributes(xAttribs); 299 break; 300 } 301 302 /// structural elements clip-path and mask. Content gets scanned, but 303 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) 304 case SVGTokenClipPathNode: 305 { 306 /// new node for ClipPath 307 mpTarget = new SvgClipPathNode(maDocument, mpTarget); 308 mpTarget->parseAttributes(xAttribs); 309 break; 310 } 311 case SVGTokenMask: 312 { 313 /// new node for Mask 314 mpTarget = new SvgMaskNode(maDocument, mpTarget); 315 mpTarget->parseAttributes(xAttribs); 316 break; 317 } 318 319 /// structural element marker 320 case SVGTokenMarker: 321 { 322 /// new node for marker 323 mpTarget = new SvgMarkerNode(maDocument, mpTarget); 324 mpTarget->parseAttributes(xAttribs); 325 break; 326 } 327 328 /// structural element pattern 329 case SVGTokenPattern: 330 { 331 /// new node for pattern 332 mpTarget = new SvgPatternNode(maDocument, mpTarget); 333 mpTarget->parseAttributes(xAttribs); 334 break; 335 } 336 337 default: 338 { 339 /// invalid token, ignore 340 #ifdef DBG_UTIL 341 myAssert( 342 rtl::OUString::createFromAscii("Unknown Base SvgToken <") + 343 aName + 344 rtl::OUString::createFromAscii("> (!)")); 345 #endif 346 break; 347 } 348 } 349 } 350 } 351 352 void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException) 353 { 354 if(aName.getLength()) 355 { 356 const SVGToken aSVGToken(StrToSVGToken(aName)); 357 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0); 358 359 switch(aSVGToken) 360 { 361 /// valid tokens for which a new one was created 362 363 /// structural elements 364 case SVGTokenDefs: 365 case SVGTokenG: 366 case SVGTokenSvg: 367 case SVGTokenSymbol: 368 case SVGTokenUse: 369 370 /// shape elements 371 case SVGTokenCircle: 372 case SVGTokenEllipse: 373 case SVGTokenLine: 374 case SVGTokenPath: 375 case SVGTokenPolygon: 376 case SVGTokenPolyline: 377 case SVGTokenRect: 378 case SVGTokenImage: 379 380 /// gradients 381 case SVGTokenLinearGradient: 382 case SVGTokenRadialGradient: 383 384 /// gradient stops 385 case SVGTokenStop: 386 387 /// text 388 case SVGTokenText: 389 case SVGTokenTspan: 390 case SVGTokenTextPath: 391 case SVGTokenTref: 392 393 /// styles (as stylesheets) 394 case SVGTokenStyle: 395 396 /// structural elements clip-path and mask 397 case SVGTokenClipPathNode: 398 case SVGTokenMask: 399 400 /// structural element marker 401 case SVGTokenMarker: 402 403 /// structural element pattern 404 case SVGTokenPattern: 405 406 /// content handling after parsing 407 { 408 if(mpTarget) 409 { 410 if(!mpTarget->getParent()) 411 { 412 // last element closing, save this tree 413 maDocument.appendNode(mpTarget); 414 } 415 416 mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); 417 } 418 else 419 { 420 OSL_ENSURE(false, "Closing token, but no context (!)"); 421 } 422 break; 423 } 424 default: 425 { 426 /// invalid token, ignore 427 } 428 } 429 430 if(pWhitespaceCheck) 431 { 432 // cleanup read strings 433 whiteSpaceHandling(pWhitespaceCheck, 0); 434 } 435 } 436 } 437 438 void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException) 439 { 440 if(mpTarget) 441 { 442 const sal_uInt32 nLength(aChars.getLength()); 443 444 if(nLength && 445 (SVGTokenText == mpTarget->getType() || 446 SVGTokenTspan == mpTarget->getType() || 447 SVGTokenTextPath == mpTarget->getType() || 448 SVGTokenStyle == mpTarget->getType())) 449 { 450 switch(mpTarget->getType()) 451 { 452 case SVGTokenText: 453 case SVGTokenTspan: 454 case SVGTokenTextPath: 455 { 456 const SvgNodeVector& rChilds = mpTarget->getChildren(); 457 SvgCharacterNode* pTarget = 0; 458 459 if(rChilds.size()) 460 { 461 pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]); 462 } 463 464 if(pTarget) 465 { 466 // concatenate to current character span 467 pTarget->concatenate(aChars); 468 } 469 else 470 { 471 // add character span as simplified tspan (no arguments) 472 // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode 473 new SvgCharacterNode(maDocument, mpTarget, aChars); 474 } 475 break; 476 } 477 case SVGTokenStyle: 478 { 479 SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); 480 481 if(rSvgStyleNode.isTextCss()) 482 { 483 // need to interpret css styles and remember them as StyleSheets 484 const ::rtl::OUString aTrimmedChars(aChars.trim()); 485 486 if(aTrimmedChars.getLength()) 487 { 488 rSvgStyleNode.addCssStyleSheet(aTrimmedChars); 489 } 490 } 491 break; 492 } 493 default: 494 { 495 // characters not used by a known node 496 break; 497 } 498 } 499 } 500 } 501 } 502 503 void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException) 504 { 505 } 506 507 void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException) 508 { 509 } 510 511 void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException) 512 { 513 } 514 } // end of namespace svgreader 515 } // end of namespace svgio 516 517 ////////////////////////////////////////////////////////////////////////////// 518 // eof 519