Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / svgio / source / svgreader / svgdocumenthandler.cxx
blob7cb91a790051fcefebced38e2be8706aa96a3b96
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/svgsymbolnode.hxx>
36 #include <svgio/svgreader/svgtextnode.hxx>
37 #include <svgio/svgreader/svgcharacternode.hxx>
38 #include <svgio/svgreader/svgtspannode.hxx>
39 #include <svgio/svgreader/svgtrefnode.hxx>
40 #include <svgio/svgreader/svgtextpathnode.hxx>
41 #include <svgio/svgreader/svgstylenode.hxx>
42 #include <svgio/svgreader/svgimagenode.hxx>
43 #include <svgio/svgreader/svgclippathnode.hxx>
44 #include <svgio/svgreader/svgmasknode.hxx>
45 #include <svgio/svgreader/svgmarkernode.hxx>
46 #include <svgio/svgreader/svgpatternnode.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 rtl::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 ::rtl::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 /// gradients
251 case SVGTokenLinearGradient:
252 case SVGTokenRadialGradient:
254 mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
255 mpTarget->parseAttributes(xAttribs);
256 break;
259 /// gradient stops
260 case SVGTokenStop:
262 mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
263 mpTarget->parseAttributes(xAttribs);
264 break;
267 /// text
268 case SVGTokenText:
270 mpTarget = new SvgTextNode(maDocument, mpTarget);
271 mpTarget->parseAttributes(xAttribs);
272 break;
274 case SVGTokenTspan:
276 mpTarget = new SvgTspanNode(maDocument, mpTarget);
277 mpTarget->parseAttributes(xAttribs);
278 break;
280 case SVGTokenTref:
282 mpTarget = new SvgTrefNode(maDocument, mpTarget);
283 mpTarget->parseAttributes(xAttribs);
284 break;
286 case SVGTokenTextPath:
288 mpTarget = new SvgTextPathNode(maDocument, mpTarget);
289 mpTarget->parseAttributes(xAttribs);
290 break;
293 /// styles (as stylesheets)
294 case SVGTokenStyle:
296 SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
297 mpTarget = pNew;
298 mpTarget->parseAttributes(xAttribs);
300 if(pNew->isTextCss())
302 maCssContents.push_back(rtl::OUString());
304 break;
307 /// structural elements clip-path and mask. Content gets scanned, but
308 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
309 case SVGTokenClipPathNode:
311 /// new node for ClipPath
312 mpTarget = new SvgClipPathNode(maDocument, mpTarget);
313 mpTarget->parseAttributes(xAttribs);
314 break;
316 case SVGTokenMask:
318 /// new node for Mask
319 mpTarget = new SvgMaskNode(maDocument, mpTarget);
320 mpTarget->parseAttributes(xAttribs);
321 break;
324 /// structural element marker
325 case SVGTokenMarker:
327 /// new node for marker
328 mpTarget = new SvgMarkerNode(maDocument, mpTarget);
329 mpTarget->parseAttributes(xAttribs);
330 break;
333 /// structural element pattern
334 case SVGTokenPattern:
336 /// new node for pattern
337 mpTarget = new SvgPatternNode(maDocument, mpTarget);
338 mpTarget->parseAttributes(xAttribs);
339 break;
342 default:
344 /// invalid token, ignore
345 #ifdef DBG_UTIL
346 myAssert(
347 rtl::OUString::createFromAscii("Unknown Base SvgToken <") +
348 aName +
349 rtl::OUString::createFromAscii("> (!)"));
350 #endif
351 break;
357 void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
359 if(aName.getLength())
361 const SVGToken aSVGToken(StrToSVGToken(aName));
362 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
363 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
365 switch(aSVGToken)
367 /// valid tokens for which a new one was created
369 /// structural elements
370 case SVGTokenDefs:
371 case SVGTokenG:
372 case SVGTokenSvg:
373 case SVGTokenSymbol:
374 case SVGTokenUse:
376 /// shape elements
377 case SVGTokenCircle:
378 case SVGTokenEllipse:
379 case SVGTokenLine:
380 case SVGTokenPath:
381 case SVGTokenPolygon:
382 case SVGTokenPolyline:
383 case SVGTokenRect:
384 case SVGTokenImage:
386 /// gradients
387 case SVGTokenLinearGradient:
388 case SVGTokenRadialGradient:
390 /// gradient stops
391 case SVGTokenStop:
393 /// text
394 case SVGTokenText:
395 case SVGTokenTspan:
396 case SVGTokenTextPath:
397 case SVGTokenTref:
399 /// styles (as stylesheets)
400 case SVGTokenStyle:
402 /// structural elements clip-path and mask
403 case SVGTokenClipPathNode:
404 case SVGTokenMask:
406 /// structural element marker
407 case SVGTokenMarker:
409 /// structural element pattern
410 case SVGTokenPattern:
412 /// content handling after parsing
414 if(mpTarget)
416 if(!mpTarget->getParent())
418 // last element closing, save this tree
419 maDocument.appendNode(mpTarget);
422 mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
424 else
426 OSL_ENSURE(false, "Closing token, but no context (!)");
428 break;
430 default:
432 /// invalid token, ignore
436 if(pCssStyle && pCssStyle->isTextCss())
438 // css style parsing
439 if(maCssContents.size())
441 // need to interpret css styles and remember them as StyleSheets
442 pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
443 maCssContents.pop_back();
445 else
447 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
451 if(pWhitespaceCheck)
453 // cleanup read strings
454 whiteSpaceHandling(pWhitespaceCheck, 0);
459 void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
461 if(mpTarget)
463 const sal_uInt32 nLength(aChars.getLength());
465 if(nLength &&
466 (SVGTokenText == mpTarget->getType() ||
467 SVGTokenTspan == mpTarget->getType() ||
468 SVGTokenTextPath == mpTarget->getType() ||
469 SVGTokenStyle == mpTarget->getType()))
471 switch(mpTarget->getType())
473 case SVGTokenText:
474 case SVGTokenTspan:
475 case SVGTokenTextPath:
477 const SvgNodeVector& rChilds = mpTarget->getChildren();
478 SvgCharacterNode* pTarget = 0;
480 if(rChilds.size())
482 pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
485 if(pTarget)
487 // concatenate to current character span
488 pTarget->concatenate(aChars);
490 else
492 // add character span as simplified tspan (no arguments)
493 // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
494 new SvgCharacterNode(maDocument, mpTarget, aChars);
496 break;
498 case SVGTokenStyle:
500 SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
502 if(rSvgStyleNode.isTextCss())
504 // collect characters for css style
505 if(maCssContents.size())
507 const ::rtl::OUString aTrimmedChars(aChars.trim());
509 if(aTrimmedChars.getLength())
511 std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1);
512 (*aString) += aTrimmedChars;
515 else
517 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
520 break;
522 default:
524 // characters not used by a known node
525 break;
532 void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
536 void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
540 void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
543 } // end of namespace svgreader
544 } // end of namespace svgio
546 //////////////////////////////////////////////////////////////////////////////
547 // eof
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */