Updated core
[LibreOffice.git] / svgio / source / svgreader / svgdocumenthandler.cxx
blob3312221bfcafaddef738edd96adb6fc5f7a533ce
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svgio/svgreader/svgdocumenthandler.hxx>
21 #include <svgio/svgreader/svgtoken.hxx>
22 #include <svgio/svgreader/svgsvgnode.hxx>
23 #include <svgio/svgreader/svggnode.hxx>
24 #include <svgio/svgreader/svgnode.hxx>
25 #include <svgio/svgreader/svgpathnode.hxx>
26 #include <svgio/svgreader/svgrectnode.hxx>
27 #include <svgio/svgreader/svggradientnode.hxx>
28 #include <svgio/svgreader/svggradientstopnode.hxx>
29 #include <svgio/svgreader/svgsymbolnode.hxx>
30 #include <svgio/svgreader/svgusenode.hxx>
31 #include <svgio/svgreader/svgcirclenode.hxx>
32 #include <svgio/svgreader/svgellipsenode.hxx>
33 #include <svgio/svgreader/svglinenode.hxx>
34 #include <svgio/svgreader/svgpolynode.hxx>
35 #include <svgio/svgreader/svgtextnode.hxx>
36 #include <svgio/svgreader/svgcharacternode.hxx>
37 #include <svgio/svgreader/svgtspannode.hxx>
38 #include <svgio/svgreader/svgtrefnode.hxx>
39 #include <svgio/svgreader/svgtextpathnode.hxx>
40 #include <svgio/svgreader/svgstylenode.hxx>
41 #include <svgio/svgreader/svgimagenode.hxx>
42 #include <svgio/svgreader/svgclippathnode.hxx>
43 #include <svgio/svgreader/svgmasknode.hxx>
44 #include <svgio/svgreader/svgmarkernode.hxx>
45 #include <svgio/svgreader/svgpatternnode.hxx>
46 #include <svgio/svgreader/svgtitledescnode.hxx>
48 //////////////////////////////////////////////////////////////////////////////
50 using namespace com::sun::star;
52 //////////////////////////////////////////////////////////////////////////////
54 namespace
56 svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast)
58 if(pNode)
60 const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren();
61 const sal_uInt32 nCount(rChilds.size());
63 for(sal_uInt32 a(0); a < nCount; a++)
65 svgio::svgreader::SvgNode* pCandidate = rChilds[a];
67 if(pCandidate)
69 switch(pCandidate->getType())
71 case svgio::svgreader::SVGTokenCharacter:
73 // clean whitespace in text span
74 svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
75 pCharNode->whiteSpaceHandling();
77 // pCharNode may have lost all text. If that's the case, ignore
78 // as invalid character node
79 if(pCharNode->getText().getLength())
81 if(pLast)
83 // add in-between whitespace (single space) to last
84 // known character node
85 pLast->addGap();
88 // remember new last corected character node
89 pLast = pCharNode;
91 break;
93 case svgio::svgreader::SVGTokenTspan:
94 case svgio::svgreader::SVGTokenTextPath:
95 case svgio::svgreader::SVGTokenTref:
97 // recursively clean whitespaces in subhierarchy
98 pLast = whiteSpaceHandling(pCandidate, pLast);
99 break;
101 default:
103 OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)");
104 break;
111 return pLast;
115 //////////////////////////////////////////////////////////////////////////////
117 namespace svgio
119 namespace svgreader
121 SvgDocHdl::SvgDocHdl(const OUString& aAbsolutePath)
122 : maDocument(aAbsolutePath),
123 mpTarget(0),
124 maCssContents()
128 SvgDocHdl::~SvgDocHdl()
130 #ifdef DBG_UTIL
131 if(mpTarget)
133 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)");
134 delete mpTarget;
136 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)");
137 #endif
140 void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
142 OSL_ENSURE(!mpTarget, "Already a target at document start (!)");
143 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)");
146 void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
148 OSL_ENSURE(!mpTarget, "Still a target at document end (!)");
149 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)");
152 void SvgDocHdl::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
154 if(aName.getLength())
156 const SVGToken aSVGToken(StrToSVGToken(aName));
158 switch(aSVGToken)
160 /// structural elements
161 case SVGTokenSymbol:
163 /// new basic node for Symbol. Content gets scanned, but
164 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
165 mpTarget = new SvgSymbolNode(maDocument, mpTarget);
166 mpTarget->parseAttributes(xAttribs);
167 break;
169 case SVGTokenDefs:
170 case SVGTokenG:
172 /// new node for Defs/G
173 mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget);
174 mpTarget->parseAttributes(xAttribs);
175 break;
177 case SVGTokenSvg:
179 /// new node for Svg
180 mpTarget = new SvgSvgNode(maDocument, mpTarget);
181 mpTarget->parseAttributes(xAttribs);
182 break;
184 case SVGTokenUse:
186 /// new node for Use
187 mpTarget = new SvgUseNode(maDocument, mpTarget);
188 mpTarget->parseAttributes(xAttribs);
189 break;
192 /// shape elements
193 case SVGTokenCircle:
195 /// new node for Circle
196 mpTarget = new SvgCircleNode(maDocument, mpTarget);
197 mpTarget->parseAttributes(xAttribs);
198 break;
200 case SVGTokenEllipse:
202 /// new node for Ellipse
203 mpTarget = new SvgEllipseNode(maDocument, mpTarget);
204 mpTarget->parseAttributes(xAttribs);
205 break;
207 case SVGTokenLine:
209 /// new node for Line
210 mpTarget = new SvgLineNode(maDocument, mpTarget);
211 mpTarget->parseAttributes(xAttribs);
212 break;
214 case SVGTokenPath:
216 /// new node for Path
217 mpTarget = new SvgPathNode(maDocument, mpTarget);
218 mpTarget->parseAttributes(xAttribs);
219 break;
221 case SVGTokenPolygon:
223 /// new node for Polygon
224 mpTarget = new SvgPolyNode(maDocument, mpTarget, false);
225 mpTarget->parseAttributes(xAttribs);
226 break;
228 case SVGTokenPolyline:
230 /// new node for Polyline
231 mpTarget = new SvgPolyNode(maDocument, mpTarget, true);
232 mpTarget->parseAttributes(xAttribs);
233 break;
235 case SVGTokenRect:
237 /// new node for Rect
238 mpTarget = new SvgRectNode(maDocument, mpTarget);
239 mpTarget->parseAttributes(xAttribs);
240 break;
242 case SVGTokenImage:
244 /// new node for Image
245 mpTarget = new SvgImageNode(maDocument, mpTarget);
246 mpTarget->parseAttributes(xAttribs);
247 break;
250 /// title and description
251 case SVGTokenTitle:
252 case SVGTokenDesc:
254 /// new node for Title and/or Desc
255 mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget);
256 break;
259 /// gradients
260 case SVGTokenLinearGradient:
261 case SVGTokenRadialGradient:
263 mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
264 mpTarget->parseAttributes(xAttribs);
265 break;
268 /// gradient stops
269 case SVGTokenStop:
271 mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
272 mpTarget->parseAttributes(xAttribs);
273 break;
276 /// text
277 case SVGTokenText:
279 mpTarget = new SvgTextNode(maDocument, mpTarget);
280 mpTarget->parseAttributes(xAttribs);
281 break;
283 case SVGTokenTspan:
285 mpTarget = new SvgTspanNode(maDocument, mpTarget);
286 mpTarget->parseAttributes(xAttribs);
287 break;
289 case SVGTokenTref:
291 mpTarget = new SvgTrefNode(maDocument, mpTarget);
292 mpTarget->parseAttributes(xAttribs);
293 break;
295 case SVGTokenTextPath:
297 mpTarget = new SvgTextPathNode(maDocument, mpTarget);
298 mpTarget->parseAttributes(xAttribs);
299 break;
302 /// styles (as stylesheets)
303 case SVGTokenStyle:
305 SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
306 mpTarget = pNew;
307 mpTarget->parseAttributes(xAttribs);
309 if(pNew->isTextCss())
311 maCssContents.push_back(OUString());
313 break;
316 /// structural elements clip-path and mask. Content gets scanned, but
317 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
318 case SVGTokenClipPathNode:
320 /// new node for ClipPath
321 mpTarget = new SvgClipPathNode(maDocument, mpTarget);
322 mpTarget->parseAttributes(xAttribs);
323 break;
325 case SVGTokenMask:
327 /// new node for Mask
328 mpTarget = new SvgMaskNode(maDocument, mpTarget);
329 mpTarget->parseAttributes(xAttribs);
330 break;
333 /// structural element marker
334 case SVGTokenMarker:
336 /// new node for marker
337 mpTarget = new SvgMarkerNode(maDocument, mpTarget);
338 mpTarget->parseAttributes(xAttribs);
339 break;
342 /// structural element pattern
343 case SVGTokenPattern:
345 /// new node for pattern
346 mpTarget = new SvgPatternNode(maDocument, mpTarget);
347 mpTarget->parseAttributes(xAttribs);
348 break;
351 default:
353 /// invalid token, ignore
354 #ifdef DBG_UTIL
355 myAssert(
356 OUString::createFromAscii("Unknown Base SvgToken <") +
357 aName +
358 OUString::createFromAscii("> (!)"));
359 #endif
360 break;
366 void SvgDocHdl::endElement( const OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
368 if(aName.getLength())
370 const SVGToken aSVGToken(StrToSVGToken(aName));
371 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
372 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
373 SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 0);
375 switch(aSVGToken)
377 /// valid tokens for which a new one was created
379 /// structural elements
380 case SVGTokenDefs:
381 case SVGTokenG:
382 case SVGTokenSvg:
383 case SVGTokenSymbol:
384 case SVGTokenUse:
386 /// shape elements
387 case SVGTokenCircle:
388 case SVGTokenEllipse:
389 case SVGTokenLine:
390 case SVGTokenPath:
391 case SVGTokenPolygon:
392 case SVGTokenPolyline:
393 case SVGTokenRect:
394 case SVGTokenImage:
396 /// title and description
397 case SVGTokenTitle:
398 case SVGTokenDesc:
400 /// gradients
401 case SVGTokenLinearGradient:
402 case SVGTokenRadialGradient:
404 /// gradient stops
405 case SVGTokenStop:
407 /// text
408 case SVGTokenText:
409 case SVGTokenTspan:
410 case SVGTokenTextPath:
411 case SVGTokenTref:
413 /// styles (as stylesheets)
414 case SVGTokenStyle:
416 /// structural elements clip-path and mask
417 case SVGTokenClipPathNode:
418 case SVGTokenMask:
420 /// structural element marker
421 case SVGTokenMarker:
423 /// structural element pattern
424 case SVGTokenPattern:
426 /// content handling after parsing
428 if(mpTarget)
430 if(!mpTarget->getParent())
432 // last element closing, save this tree
433 maDocument.appendNode(mpTarget);
436 mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
438 else
440 OSL_ENSURE(false, "Closing token, but no context (!)");
442 break;
444 default:
446 /// invalid token, ignore
450 if(pSvgTitleDescNode && mpTarget)
452 const OUString aText(pSvgTitleDescNode->getText());
454 if(aText.getLength())
456 if(SVGTokenTitle == aSVGToken)
458 mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText);
460 else // if(SVGTokenDesc == aSVGToken)
462 mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText);
467 if(pCssStyle && pCssStyle->isTextCss())
469 // css style parsing
470 if(maCssContents.size())
472 // need to interpret css styles and remember them as StyleSheets
473 pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
474 maCssContents.pop_back();
476 else
478 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
482 if(pWhitespaceCheck)
484 // cleanup read strings
485 whiteSpaceHandling(pWhitespaceCheck, 0);
490 void SvgDocHdl::characters( const OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
492 const sal_uInt32 nLength(aChars.getLength());
494 if(mpTarget && nLength)
496 switch(mpTarget->getType())
498 case SVGTokenText:
499 case SVGTokenTspan:
500 case SVGTokenTextPath:
502 const SvgNodeVector& rChilds = mpTarget->getChildren();
503 SvgCharacterNode* pTarget = 0;
505 if(rChilds.size())
507 pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
510 if(pTarget)
512 // concatenate to current character span
513 pTarget->concatenate(aChars);
515 else
517 // add character span as simplified tspan (no arguments)
518 // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
519 new SvgCharacterNode(maDocument, mpTarget, aChars);
521 break;
523 case SVGTokenStyle:
525 SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
527 if(rSvgStyleNode.isTextCss())
529 // collect characters for css style
530 if(maCssContents.size())
532 const OUString aTrimmedChars(aChars.trim());
534 if(aTrimmedChars.getLength())
536 std::vector< OUString >::iterator aString(maCssContents.end() - 1);
537 (*aString) += aTrimmedChars;
540 else
542 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
545 break;
547 case SVGTokenTitle:
548 case SVGTokenDesc:
550 SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget);
552 // add text directly to SvgTitleDescNode
553 rSvgTitleDescNode.concatenate(aChars);
554 break;
556 default:
558 // characters not used by a known node
559 break;
565 void SvgDocHdl::ignorableWhitespace(const OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
569 void SvgDocHdl::processingInstruction(const OUString& /*aTarget*/, const OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
573 void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
576 } // end of namespace svgreader
577 } // end of namespace svgio
579 //////////////////////////////////////////////////////////////////////////////
580 // eof
582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */