Stop leaking all ScPostIt instances.
[LibreOffice.git] / svgio / source / svgreader / svgdocumenthandler.cxx
blobf8637ea8b9e44c01c0af478898297de1fa27682c
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().isEmpty())
81 if(pLast)
83 bool bAddGap(true);
84 static bool bNoGapsForBaselineShift(true);
86 if(bNoGapsForBaselineShift)
88 // With this option a baseline shift between two char parts ('words')
89 // will not add a space 'gap' to the end of the (non-last) word. This
90 // seems to be the standard behaviour, see last bugdoc attached #122524#
91 const svgio::svgreader::SvgStyleAttributes* pStyleLast = pLast->getSvgStyleAttributes();
92 const svgio::svgreader::SvgStyleAttributes* pStyleCurrent = pCandidate->getSvgStyleAttributes();
94 if(pStyleLast && pStyleCurrent && pStyleLast->getBaselineShift() != pStyleCurrent->getBaselineShift())
96 bAddGap = false;
100 // add in-between whitespace (single space) to last
101 // known character node
102 if(bAddGap)
104 pLast->addGap();
108 // remember new last corected character node
109 pLast = pCharNode;
111 break;
113 case svgio::svgreader::SVGTokenTspan:
114 case svgio::svgreader::SVGTokenTextPath:
115 case svgio::svgreader::SVGTokenTref:
117 // recursively clean whitespaces in subhierarchy
118 pLast = whiteSpaceHandling(pCandidate, pLast);
119 break;
121 default:
123 OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)");
124 break;
131 return pLast;
135 //////////////////////////////////////////////////////////////////////////////
137 namespace svgio
139 namespace svgreader
141 SvgDocHdl::SvgDocHdl(const OUString& aAbsolutePath)
142 : maDocument(aAbsolutePath),
143 mpTarget(0),
144 maCssContents()
148 SvgDocHdl::~SvgDocHdl()
150 #ifdef DBG_UTIL
151 if(mpTarget)
153 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)");
154 delete mpTarget;
156 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)");
157 #endif
160 void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
162 OSL_ENSURE(!mpTarget, "Already a target at document start (!)");
163 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)");
166 void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException)
168 OSL_ENSURE(!mpTarget, "Still a target at document end (!)");
169 OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)");
172 void SvgDocHdl::startElement( const OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
174 if(!aName.isEmpty())
176 const SVGToken aSVGToken(StrToSVGToken(aName));
178 switch(aSVGToken)
180 /// structural elements
181 case SVGTokenSymbol:
183 /// new basic node for Symbol. Content gets scanned, but
184 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
185 mpTarget = new SvgSymbolNode(maDocument, mpTarget);
186 mpTarget->parseAttributes(xAttribs);
187 break;
189 case SVGTokenDefs:
190 case SVGTokenG:
192 /// new node for Defs/G
193 mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget);
194 mpTarget->parseAttributes(xAttribs);
195 break;
197 case SVGTokenSvg:
199 /// new node for Svg
200 mpTarget = new SvgSvgNode(maDocument, mpTarget);
201 mpTarget->parseAttributes(xAttribs);
202 break;
204 case SVGTokenUse:
206 /// new node for Use
207 mpTarget = new SvgUseNode(maDocument, mpTarget);
208 mpTarget->parseAttributes(xAttribs);
209 break;
212 /// shape elements
213 case SVGTokenCircle:
215 /// new node for Circle
216 mpTarget = new SvgCircleNode(maDocument, mpTarget);
217 mpTarget->parseAttributes(xAttribs);
218 break;
220 case SVGTokenEllipse:
222 /// new node for Ellipse
223 mpTarget = new SvgEllipseNode(maDocument, mpTarget);
224 mpTarget->parseAttributes(xAttribs);
225 break;
227 case SVGTokenLine:
229 /// new node for Line
230 mpTarget = new SvgLineNode(maDocument, mpTarget);
231 mpTarget->parseAttributes(xAttribs);
232 break;
234 case SVGTokenPath:
236 /// new node for Path
237 mpTarget = new SvgPathNode(maDocument, mpTarget);
238 mpTarget->parseAttributes(xAttribs);
239 break;
241 case SVGTokenPolygon:
243 /// new node for Polygon
244 mpTarget = new SvgPolyNode(maDocument, mpTarget, false);
245 mpTarget->parseAttributes(xAttribs);
246 break;
248 case SVGTokenPolyline:
250 /// new node for Polyline
251 mpTarget = new SvgPolyNode(maDocument, mpTarget, true);
252 mpTarget->parseAttributes(xAttribs);
253 break;
255 case SVGTokenRect:
257 /// new node for Rect
258 mpTarget = new SvgRectNode(maDocument, mpTarget);
259 mpTarget->parseAttributes(xAttribs);
260 break;
262 case SVGTokenImage:
264 /// new node for Image
265 mpTarget = new SvgImageNode(maDocument, mpTarget);
266 mpTarget->parseAttributes(xAttribs);
267 break;
270 /// title and description
271 case SVGTokenTitle:
272 case SVGTokenDesc:
274 /// new node for Title and/or Desc
275 mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget);
276 break;
279 /// gradients
280 case SVGTokenLinearGradient:
281 case SVGTokenRadialGradient:
283 mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
284 mpTarget->parseAttributes(xAttribs);
285 break;
288 /// gradient stops
289 case SVGTokenStop:
291 mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
292 mpTarget->parseAttributes(xAttribs);
293 break;
296 /// text
297 case SVGTokenText:
299 mpTarget = new SvgTextNode(maDocument, mpTarget);
300 mpTarget->parseAttributes(xAttribs);
301 break;
303 case SVGTokenTspan:
305 mpTarget = new SvgTspanNode(maDocument, mpTarget);
306 mpTarget->parseAttributes(xAttribs);
307 break;
309 case SVGTokenTref:
311 mpTarget = new SvgTrefNode(maDocument, mpTarget);
312 mpTarget->parseAttributes(xAttribs);
313 break;
315 case SVGTokenTextPath:
317 mpTarget = new SvgTextPathNode(maDocument, mpTarget);
318 mpTarget->parseAttributes(xAttribs);
319 break;
322 /// styles (as stylesheets)
323 case SVGTokenStyle:
325 SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
326 mpTarget = pNew;
327 mpTarget->parseAttributes(xAttribs);
329 if(pNew->isTextCss())
331 maCssContents.push_back(OUString());
333 break;
336 /// structural elements clip-path and mask. Content gets scanned, but
337 /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
338 case SVGTokenClipPathNode:
340 /// new node for ClipPath
341 mpTarget = new SvgClipPathNode(maDocument, mpTarget);
342 mpTarget->parseAttributes(xAttribs);
343 break;
345 case SVGTokenMask:
347 /// new node for Mask
348 mpTarget = new SvgMaskNode(maDocument, mpTarget);
349 mpTarget->parseAttributes(xAttribs);
350 break;
353 /// structural element marker
354 case SVGTokenMarker:
356 /// new node for marker
357 mpTarget = new SvgMarkerNode(maDocument, mpTarget);
358 mpTarget->parseAttributes(xAttribs);
359 break;
362 /// structural element pattern
363 case SVGTokenPattern:
365 /// new node for pattern
366 mpTarget = new SvgPatternNode(maDocument, mpTarget);
367 mpTarget->parseAttributes(xAttribs);
368 break;
371 default:
373 /// invalid token, ignore
374 #ifdef DBG_UTIL
375 myAssert(
376 OUString::createFromAscii("Unknown Base SvgToken <") +
377 aName +
378 OUString::createFromAscii("> (!)"));
379 #endif
380 break;
386 void SvgDocHdl::endElement( const OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
388 if(!aName.isEmpty())
390 const SVGToken aSVGToken(StrToSVGToken(aName));
391 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
392 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
393 SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 0);
395 switch(aSVGToken)
397 /// valid tokens for which a new one was created
399 /// structural elements
400 case SVGTokenDefs:
401 case SVGTokenG:
402 case SVGTokenSvg:
403 case SVGTokenSymbol:
404 case SVGTokenUse:
406 /// shape elements
407 case SVGTokenCircle:
408 case SVGTokenEllipse:
409 case SVGTokenLine:
410 case SVGTokenPath:
411 case SVGTokenPolygon:
412 case SVGTokenPolyline:
413 case SVGTokenRect:
414 case SVGTokenImage:
416 /// title and description
417 case SVGTokenTitle:
418 case SVGTokenDesc:
420 /// gradients
421 case SVGTokenLinearGradient:
422 case SVGTokenRadialGradient:
424 /// gradient stops
425 case SVGTokenStop:
427 /// text
428 case SVGTokenText:
429 case SVGTokenTspan:
430 case SVGTokenTextPath:
431 case SVGTokenTref:
433 /// styles (as stylesheets)
434 case SVGTokenStyle:
436 /// structural elements clip-path and mask
437 case SVGTokenClipPathNode:
438 case SVGTokenMask:
440 /// structural element marker
441 case SVGTokenMarker:
443 /// structural element pattern
444 case SVGTokenPattern:
446 /// content handling after parsing
448 if(mpTarget)
450 if(!mpTarget->getParent())
452 // last element closing, save this tree
453 maDocument.appendNode(mpTarget);
456 mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
458 else
460 OSL_ENSURE(false, "Closing token, but no context (!)");
462 break;
464 default:
466 /// invalid token, ignore
470 if(pSvgTitleDescNode && mpTarget)
472 const OUString aText(pSvgTitleDescNode->getText());
474 if(!aText.isEmpty())
476 if(SVGTokenTitle == aSVGToken)
478 mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText);
480 else // if(SVGTokenDesc == aSVGToken)
482 mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText);
487 if(pCssStyle && pCssStyle->isTextCss())
489 // css style parsing
490 if(maCssContents.size())
492 // need to interpret css styles and remember them as StyleSheets
493 pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
494 maCssContents.pop_back();
496 else
498 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
502 if(pWhitespaceCheck)
504 // cleanup read strings
505 whiteSpaceHandling(pWhitespaceCheck, 0);
510 void SvgDocHdl::characters( const OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
512 const sal_uInt32 nLength(aChars.getLength());
514 if(mpTarget && nLength)
516 switch(mpTarget->getType())
518 case SVGTokenText:
519 case SVGTokenTspan:
520 case SVGTokenTextPath:
522 const SvgNodeVector& rChilds = mpTarget->getChildren();
523 SvgCharacterNode* pTarget = 0;
525 if(rChilds.size())
527 pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
530 if(pTarget)
532 // concatenate to current character span
533 pTarget->concatenate(aChars);
535 else
537 // add character span as simplified tspan (no arguments)
538 // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
539 new SvgCharacterNode(maDocument, mpTarget, aChars);
541 break;
543 case SVGTokenStyle:
545 SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
547 if(rSvgStyleNode.isTextCss())
549 // collect characters for css style
550 if(maCssContents.size())
552 const OUString aTrimmedChars(aChars.trim());
554 if(!aTrimmedChars.isEmpty())
556 std::vector< OUString >::iterator aString(maCssContents.end() - 1);
557 (*aString) += aTrimmedChars;
560 else
562 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
565 break;
567 case SVGTokenTitle:
568 case SVGTokenDesc:
570 SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget);
572 // add text directly to SvgTitleDescNode
573 rSvgTitleDescNode.concatenate(aChars);
574 break;
576 default:
578 // characters not used by a known node
579 break;
585 void SvgDocHdl::ignorableWhitespace(const OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
589 void SvgDocHdl::processingInstruction(const OUString& /*aTarget*/, const OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
593 void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
596 } // end of namespace svgreader
597 } // end of namespace svgio
599 //////////////////////////////////////////////////////////////////////////////
600 // eof
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */