1ddde725dSArmin Le Grand /**************************************************************
2ddde725dSArmin Le Grand  *
3ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5ddde725dSArmin Le Grand  * distributed with this work for additional information
6ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10ddde725dSArmin Le Grand  *
11ddde725dSArmin Le Grand  *   http://www.apache.org/licenses/LICENSE-2.0
12ddde725dSArmin Le Grand  *
13ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18ddde725dSArmin Le Grand  * under the License.
19ddde725dSArmin Le Grand  *
20ddde725dSArmin Le Grand  *************************************************************/
21ddde725dSArmin Le Grand 
22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23ddde725dSArmin Le Grand #include "precompiled_svgio.hxx"
24ddde725dSArmin Le Grand 
25ddde725dSArmin Le Grand #include <svgio/svgreader/svgdocumenthandler.hxx>
26ddde725dSArmin Le Grand #include <svgio/svgreader/svgtoken.hxx>
27ddde725dSArmin Le Grand #include <svgio/svgreader/svgsvgnode.hxx>
28ddde725dSArmin Le Grand #include <svgio/svgreader/svggnode.hxx>
29ddde725dSArmin Le Grand #include <svgio/svgreader/svgnode.hxx>
30ddde725dSArmin Le Grand #include <svgio/svgreader/svgpathnode.hxx>
31ddde725dSArmin Le Grand #include <svgio/svgreader/svgrectnode.hxx>
32ddde725dSArmin Le Grand #include <svgio/svgreader/svggradientnode.hxx>
33ddde725dSArmin Le Grand #include <svgio/svgreader/svggradientstopnode.hxx>
34ddde725dSArmin Le Grand #include <svgio/svgreader/svgsymbolnode.hxx>
35ddde725dSArmin Le Grand #include <svgio/svgreader/svgusenode.hxx>
36ddde725dSArmin Le Grand #include <svgio/svgreader/svgcirclenode.hxx>
37ddde725dSArmin Le Grand #include <svgio/svgreader/svgellipsenode.hxx>
38ddde725dSArmin Le Grand #include <svgio/svgreader/svglinenode.hxx>
39ddde725dSArmin Le Grand #include <svgio/svgreader/svgpolynode.hxx>
40ddde725dSArmin Le Grand #include <svgio/svgreader/svgsymbolnode.hxx>
41ddde725dSArmin Le Grand #include <svgio/svgreader/svgtextnode.hxx>
42ddde725dSArmin Le Grand #include <svgio/svgreader/svgcharacternode.hxx>
43ddde725dSArmin Le Grand #include <svgio/svgreader/svgtspannode.hxx>
44ddde725dSArmin Le Grand #include <svgio/svgreader/svgtrefnode.hxx>
45ddde725dSArmin Le Grand #include <svgio/svgreader/svgtextpathnode.hxx>
46ddde725dSArmin Le Grand #include <svgio/svgreader/svgstylenode.hxx>
47ddde725dSArmin Le Grand #include <svgio/svgreader/svgimagenode.hxx>
48ddde725dSArmin Le Grand #include <svgio/svgreader/svgclippathnode.hxx>
49ddde725dSArmin Le Grand #include <svgio/svgreader/svgmasknode.hxx>
50ddde725dSArmin Le Grand #include <svgio/svgreader/svgmarkernode.hxx>
51ddde725dSArmin Le Grand #include <svgio/svgreader/svgpatternnode.hxx>
52025b0597SArmin Le Grand #include <svgio/svgreader/svgtitledescnode.hxx>
53ddde725dSArmin Le Grand 
54ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
55ddde725dSArmin Le Grand 
56ddde725dSArmin Le Grand using namespace com::sun::star;
57ddde725dSArmin Le Grand 
58ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
59ddde725dSArmin Le Grand 
60ddde725dSArmin Le Grand namespace
61ddde725dSArmin Le Grand {
62ddde725dSArmin Le Grand     svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast)
63ddde725dSArmin Le Grand     {
64ddde725dSArmin Le Grand         if(pNode)
65ddde725dSArmin Le Grand         {
66ddde725dSArmin Le Grand             const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren();
67ddde725dSArmin Le Grand             const sal_uInt32 nCount(rChilds.size());
68ddde725dSArmin Le Grand 
69ddde725dSArmin Le Grand             for(sal_uInt32 a(0); a < nCount; a++)
70ddde725dSArmin Le Grand             {
71ddde725dSArmin Le Grand                 svgio::svgreader::SvgNode* pCandidate = rChilds[a];
72ddde725dSArmin Le Grand 
73ddde725dSArmin Le Grand                 if(pCandidate)
74ddde725dSArmin Le Grand                 {
75ddde725dSArmin Le Grand                     switch(pCandidate->getType())
76ddde725dSArmin Le Grand                     {
77ddde725dSArmin Le Grand                         case svgio::svgreader::SVGTokenCharacter:
78ddde725dSArmin Le Grand                         {
79ddde725dSArmin Le Grand                             // clean whitespace in text span
80ddde725dSArmin Le Grand                             svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
81ddde725dSArmin Le Grand                             pCharNode->whiteSpaceHandling();
82ddde725dSArmin Le Grand 
83ddde725dSArmin Le Grand                             // pCharNode may have lost all text. If that's the case, ignore
84ddde725dSArmin Le Grand                             // as invalid character node
85ddde725dSArmin Le Grand                             if(pCharNode->getText().getLength())
86ddde725dSArmin Le Grand                             {
87ddde725dSArmin Le Grand                                 if(pLast)
88ddde725dSArmin Le Grand                                 {
8986d02030SArmin Le Grand                                     bool bAddGap(true);
9086d02030SArmin Le Grand                                     static bool bNoGapsForBaselineShift(true);
9186d02030SArmin Le Grand 
9286d02030SArmin Le Grand                                     if(bNoGapsForBaselineShift)
9386d02030SArmin Le Grand                                     {
9486d02030SArmin Le Grand                                         // With this option a baseline shift between two char parts ('words')
9586d02030SArmin Le Grand                                         // will not add a space 'gap' to the end of the (non-last) word. This
9686d02030SArmin Le Grand                                         // seems to be the standard behaviour, see last bugdoc attached #122524#
9786d02030SArmin Le Grand                                         const svgio::svgreader::SvgStyleAttributes* pStyleLast = pLast->getSvgStyleAttributes();
9886d02030SArmin Le Grand                                         const svgio::svgreader::SvgStyleAttributes* pStyleCurrent = pCandidate->getSvgStyleAttributes();
9986d02030SArmin Le Grand 
10086d02030SArmin Le Grand                                         if(pStyleLast && pStyleCurrent && pStyleLast->getBaselineShift() != pStyleCurrent->getBaselineShift())
10186d02030SArmin Le Grand                                         {
10286d02030SArmin Le Grand                                             bAddGap = false;
10386d02030SArmin Le Grand                                         }
10486d02030SArmin Le Grand                                     }
10586d02030SArmin Le Grand 
106ddde725dSArmin Le Grand                                     // add in-between whitespace (single space) to last
107ddde725dSArmin Le Grand                                     // known character node
10886d02030SArmin Le Grand                                     if(bAddGap)
10986d02030SArmin Le Grand                                     {
11086d02030SArmin Le Grand                                         pLast->addGap();
11186d02030SArmin Le Grand                                     }
112ddde725dSArmin Le Grand                                 }
113ddde725dSArmin Le Grand 
114ddde725dSArmin Le Grand                                 // remember new last corected character node
115ddde725dSArmin Le Grand                                 pLast = pCharNode;
116ddde725dSArmin Le Grand                             }
117ddde725dSArmin Le Grand                             break;
118ddde725dSArmin Le Grand                         }
119ddde725dSArmin Le Grand                         case svgio::svgreader::SVGTokenTspan:
120ddde725dSArmin Le Grand                         case svgio::svgreader::SVGTokenTextPath:
121ddde725dSArmin Le Grand                         case svgio::svgreader::SVGTokenTref:
122ddde725dSArmin Le Grand                         {
123ddde725dSArmin Le Grand                             // recursively clean whitespaces in subhierarchy
124ddde725dSArmin Le Grand                             pLast = whiteSpaceHandling(pCandidate, pLast);
125ddde725dSArmin Le Grand                             break;
126ddde725dSArmin Le Grand                         }
127ddde725dSArmin Le Grand                         default:
128ddde725dSArmin Le Grand                         {
129ddde725dSArmin Le Grand                             OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)");
130ddde725dSArmin Le Grand                             break;
131ddde725dSArmin Le Grand                         }
132ddde725dSArmin Le Grand                     }
133ddde725dSArmin Le Grand                 }
134ddde725dSArmin Le Grand             }
135ddde725dSArmin Le Grand         }
136ddde725dSArmin Le Grand 
137ddde725dSArmin Le Grand         return pLast;
138ddde725dSArmin Le Grand     }
139ddde725dSArmin Le Grand }
140ddde725dSArmin Le Grand 
141ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
142ddde725dSArmin Le Grand 
143ddde725dSArmin Le Grand namespace svgio
144ddde725dSArmin Le Grand {
145ddde725dSArmin Le Grand     namespace svgreader
146ddde725dSArmin Le Grand     {
147ddde725dSArmin Le Grand         SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath)
148ddde725dSArmin Le Grand         :   maDocument(aAbsolutePath),
1493aaca8a3SArmin Le Grand             mpTarget(0),
1503aaca8a3SArmin Le Grand             maCssContents()
151ddde725dSArmin Le Grand         {
152ddde725dSArmin Le Grand         }
153ddde725dSArmin Le Grand 
154ddde725dSArmin Le Grand         SvgDocHdl::~SvgDocHdl()
155ddde725dSArmin Le Grand         {
156ddde725dSArmin Le Grand #ifdef DBG_UTIL
157ddde725dSArmin Le Grand             if(mpTarget)
158ddde725dSArmin Le Grand             {
159ddde725dSArmin Le Grand                 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)");
160ddde725dSArmin Le Grand                 delete mpTarget;
161ddde725dSArmin Le Grand             }
1623aaca8a3SArmin Le Grand             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)");
163ddde725dSArmin Le Grand #endif
164ddde725dSArmin Le Grand         }
165ddde725dSArmin Le Grand 
166ddde725dSArmin Le Grand         void SvgDocHdl::startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
167ddde725dSArmin Le Grand         {
168ddde725dSArmin Le Grand             OSL_ENSURE(!mpTarget, "Already a target at document start (!)");
1693aaca8a3SArmin Le Grand             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)");
170ddde725dSArmin Le Grand         }
171ddde725dSArmin Le Grand 
172ddde725dSArmin Le Grand         void SvgDocHdl::endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
173ddde725dSArmin Le Grand         {
174ddde725dSArmin Le Grand             OSL_ENSURE(!mpTarget, "Still a target at document end (!)");
1753aaca8a3SArmin Le Grand             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)");
176ddde725dSArmin Le Grand         }
177ddde725dSArmin Le Grand 
178ddde725dSArmin Le Grand         void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
179ddde725dSArmin Le Grand         {
180ddde725dSArmin Le Grand             if(aName.getLength())
181ddde725dSArmin Le Grand             {
182*52cb04b8SArmin Le Grand                 const SVGToken aSVGToken(StrToSVGToken(aName, false));
183ddde725dSArmin Le Grand 
184ddde725dSArmin Le Grand                 switch(aSVGToken)
185ddde725dSArmin Le Grand                 {
186ddde725dSArmin Le Grand                     /// structural elements
187ddde725dSArmin Le Grand                     case SVGTokenSymbol:
188ddde725dSArmin Le Grand                     {
189ddde725dSArmin Le Grand                         /// new basic node for Symbol. Content gets scanned, but
190ddde725dSArmin Le Grand                         /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
191ddde725dSArmin Le Grand                         mpTarget = new SvgSymbolNode(maDocument, mpTarget);
192ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
193ddde725dSArmin Le Grand                         break;
194ddde725dSArmin Le Grand                     }
195ddde725dSArmin Le Grand                     case SVGTokenDefs:
196ddde725dSArmin Le Grand                     case SVGTokenG:
197ddde725dSArmin Le Grand                     {
198ddde725dSArmin Le Grand                         /// new node for Defs/G
199ddde725dSArmin Le Grand                         mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget);
200ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
201ddde725dSArmin Le Grand                         break;
202ddde725dSArmin Le Grand                     }
203ddde725dSArmin Le Grand                     case SVGTokenSvg:
204ddde725dSArmin Le Grand                     {
205ddde725dSArmin Le Grand                         /// new node for Svg
206ddde725dSArmin Le Grand                         mpTarget = new SvgSvgNode(maDocument, mpTarget);
207ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
208ddde725dSArmin Le Grand                         break;
209ddde725dSArmin Le Grand                     }
210ddde725dSArmin Le Grand                     case SVGTokenUse:
211ddde725dSArmin Le Grand                     {
212ddde725dSArmin Le Grand                         /// new node for Use
213ddde725dSArmin Le Grand                         mpTarget = new SvgUseNode(maDocument, mpTarget);
214ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
215ddde725dSArmin Le Grand                         break;
216ddde725dSArmin Le Grand                     }
217ddde725dSArmin Le Grand 
218ddde725dSArmin Le Grand                     /// shape elements
219ddde725dSArmin Le Grand                     case SVGTokenCircle:
220ddde725dSArmin Le Grand                     {
221ddde725dSArmin Le Grand                         /// new node for Circle
222ddde725dSArmin Le Grand                         mpTarget = new SvgCircleNode(maDocument, mpTarget);
223ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
224ddde725dSArmin Le Grand                         break;
225ddde725dSArmin Le Grand                     }
226ddde725dSArmin Le Grand                     case SVGTokenEllipse:
227ddde725dSArmin Le Grand                     {
228ddde725dSArmin Le Grand                         /// new node for Ellipse
229ddde725dSArmin Le Grand                         mpTarget = new SvgEllipseNode(maDocument, mpTarget);
230ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
231ddde725dSArmin Le Grand                         break;
232ddde725dSArmin Le Grand                     }
233ddde725dSArmin Le Grand                     case SVGTokenLine:
234ddde725dSArmin Le Grand                     {
235ddde725dSArmin Le Grand                         /// new node for Line
236ddde725dSArmin Le Grand                         mpTarget = new SvgLineNode(maDocument, mpTarget);
237ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
238ddde725dSArmin Le Grand                         break;
239ddde725dSArmin Le Grand                     }
240ddde725dSArmin Le Grand                     case SVGTokenPath:
241ddde725dSArmin Le Grand                     {
242ddde725dSArmin Le Grand                         /// new node for Path
243ddde725dSArmin Le Grand                         mpTarget = new SvgPathNode(maDocument, mpTarget);
244ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
245ddde725dSArmin Le Grand                         break;
246ddde725dSArmin Le Grand                     }
247ddde725dSArmin Le Grand                     case SVGTokenPolygon:
248ddde725dSArmin Le Grand                     {
249ddde725dSArmin Le Grand                         /// new node for Polygon
250ddde725dSArmin Le Grand                         mpTarget = new SvgPolyNode(maDocument, mpTarget, false);
251ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
252ddde725dSArmin Le Grand                         break;
253ddde725dSArmin Le Grand                     }
254ddde725dSArmin Le Grand                     case SVGTokenPolyline:
255ddde725dSArmin Le Grand                     {
256ddde725dSArmin Le Grand                         /// new node for Polyline
257ddde725dSArmin Le Grand                         mpTarget = new SvgPolyNode(maDocument, mpTarget, true);
258ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
259ddde725dSArmin Le Grand                         break;
260ddde725dSArmin Le Grand                     }
261ddde725dSArmin Le Grand                     case SVGTokenRect:
262ddde725dSArmin Le Grand                     {
263ddde725dSArmin Le Grand                         /// new node for Rect
264ddde725dSArmin Le Grand                         mpTarget = new SvgRectNode(maDocument, mpTarget);
265ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
266ddde725dSArmin Le Grand                         break;
267ddde725dSArmin Le Grand                     }
268ddde725dSArmin Le Grand                     case SVGTokenImage:
269ddde725dSArmin Le Grand                     {
270ddde725dSArmin Le Grand                         /// new node for Image
271ddde725dSArmin Le Grand                         mpTarget = new SvgImageNode(maDocument, mpTarget);
272ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
273ddde725dSArmin Le Grand                         break;
274ddde725dSArmin Le Grand                     }
275ddde725dSArmin Le Grand 
276025b0597SArmin Le Grand                     /// title and description
277025b0597SArmin Le Grand                     case SVGTokenTitle:
278025b0597SArmin Le Grand                     case SVGTokenDesc:
279025b0597SArmin Le Grand                     {
280025b0597SArmin Le Grand                         /// new node for Title and/or Desc
281025b0597SArmin Le Grand                         mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget);
282025b0597SArmin Le Grand                         break;
283025b0597SArmin Le Grand                     }
284025b0597SArmin Le Grand 
285ddde725dSArmin Le Grand                     /// gradients
286ddde725dSArmin Le Grand                     case SVGTokenLinearGradient:
287ddde725dSArmin Le Grand                     case SVGTokenRadialGradient:
288ddde725dSArmin Le Grand                     {
289ddde725dSArmin Le Grand                         mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
290ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
291ddde725dSArmin Le Grand                         break;
292ddde725dSArmin Le Grand                     }
293ddde725dSArmin Le Grand 
294ddde725dSArmin Le Grand                     /// gradient stops
295ddde725dSArmin Le Grand                     case SVGTokenStop:
296ddde725dSArmin Le Grand                     {
297ddde725dSArmin Le Grand                         mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
298ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
299ddde725dSArmin Le Grand                         break;
300ddde725dSArmin Le Grand                     }
301ddde725dSArmin Le Grand 
302ddde725dSArmin Le Grand                     /// text
303ddde725dSArmin Le Grand                     case SVGTokenText:
304ddde725dSArmin Le Grand                     {
305ddde725dSArmin Le Grand                         mpTarget = new SvgTextNode(maDocument, mpTarget);
306ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
307ddde725dSArmin Le Grand                         break;
308ddde725dSArmin Le Grand                     }
309ddde725dSArmin Le Grand                     case SVGTokenTspan:
310ddde725dSArmin Le Grand                     {
311ddde725dSArmin Le Grand                         mpTarget = new SvgTspanNode(maDocument, mpTarget);
312ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
313ddde725dSArmin Le Grand                         break;
314ddde725dSArmin Le Grand                     }
315ddde725dSArmin Le Grand                     case SVGTokenTref:
316ddde725dSArmin Le Grand                     {
317ddde725dSArmin Le Grand                         mpTarget = new SvgTrefNode(maDocument, mpTarget);
318ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
319ddde725dSArmin Le Grand                         break;
320ddde725dSArmin Le Grand                     }
321ddde725dSArmin Le Grand                     case SVGTokenTextPath:
322ddde725dSArmin Le Grand                     {
323ddde725dSArmin Le Grand                         mpTarget = new SvgTextPathNode(maDocument, mpTarget);
324ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
325ddde725dSArmin Le Grand                         break;
326ddde725dSArmin Le Grand                     }
327ddde725dSArmin Le Grand 
328ddde725dSArmin Le Grand                     /// styles (as stylesheets)
329ddde725dSArmin Le Grand                     case SVGTokenStyle:
330ddde725dSArmin Le Grand                     {
3313aaca8a3SArmin Le Grand                         SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
3323aaca8a3SArmin Le Grand                         mpTarget = pNew;
333ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
3343aaca8a3SArmin Le Grand 
3353aaca8a3SArmin Le Grand                         if(pNew->isTextCss())
3363aaca8a3SArmin Le Grand                         {
3373aaca8a3SArmin Le Grand                             maCssContents.push_back(rtl::OUString());
3383aaca8a3SArmin Le Grand                         }
339ddde725dSArmin Le Grand                         break;
340ddde725dSArmin Le Grand                     }
341ddde725dSArmin Le Grand 
342ddde725dSArmin Le Grand                     /// structural elements clip-path and mask. Content gets scanned, but
343ddde725dSArmin Le Grand                     /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
344ddde725dSArmin Le Grand                     case SVGTokenClipPathNode:
345ddde725dSArmin Le Grand                     {
346ddde725dSArmin Le Grand                         /// new node for ClipPath
347ddde725dSArmin Le Grand                         mpTarget = new SvgClipPathNode(maDocument, mpTarget);
348ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
349ddde725dSArmin Le Grand                         break;
350ddde725dSArmin Le Grand                     }
351ddde725dSArmin Le Grand                     case SVGTokenMask:
352ddde725dSArmin Le Grand                     {
353ddde725dSArmin Le Grand                         /// new node for Mask
354ddde725dSArmin Le Grand                         mpTarget = new SvgMaskNode(maDocument, mpTarget);
355ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
356ddde725dSArmin Le Grand                         break;
357ddde725dSArmin Le Grand                     }
358ddde725dSArmin Le Grand 
359ddde725dSArmin Le Grand                     /// structural element marker
360ddde725dSArmin Le Grand                     case SVGTokenMarker:
361ddde725dSArmin Le Grand                     {
362ddde725dSArmin Le Grand                         /// new node for marker
363ddde725dSArmin Le Grand                         mpTarget = new SvgMarkerNode(maDocument, mpTarget);
364ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
365ddde725dSArmin Le Grand                         break;
366ddde725dSArmin Le Grand                     }
367ddde725dSArmin Le Grand 
368ddde725dSArmin Le Grand                     /// structural element pattern
369ddde725dSArmin Le Grand                     case SVGTokenPattern:
370ddde725dSArmin Le Grand                     {
371ddde725dSArmin Le Grand                         /// new node for pattern
372ddde725dSArmin Le Grand                         mpTarget = new SvgPatternNode(maDocument, mpTarget);
373ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
374ddde725dSArmin Le Grand                         break;
375ddde725dSArmin Le Grand                     }
376ddde725dSArmin Le Grand 
377ddde725dSArmin Le Grand                     default:
378ddde725dSArmin Le Grand                     {
379ddde725dSArmin Le Grand                         /// invalid token, ignore
380ddde725dSArmin Le Grand #ifdef DBG_UTIL
381ddde725dSArmin Le Grand                         myAssert(
382ddde725dSArmin Le Grand                             rtl::OUString::createFromAscii("Unknown Base SvgToken <") +
383ddde725dSArmin Le Grand                             aName +
384ddde725dSArmin Le Grand                             rtl::OUString::createFromAscii("> (!)"));
385ddde725dSArmin Le Grand #endif
386ddde725dSArmin Le Grand                         break;
387ddde725dSArmin Le Grand                     }
388ddde725dSArmin Le Grand                 }
389ddde725dSArmin Le Grand             }
390ddde725dSArmin Le Grand         }
391ddde725dSArmin Le Grand 
392ddde725dSArmin Le Grand         void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
393ddde725dSArmin Le Grand         {
394ddde725dSArmin Le Grand             if(aName.getLength())
395ddde725dSArmin Le Grand             {
396*52cb04b8SArmin Le Grand                 const SVGToken aSVGToken(StrToSVGToken(aName, false));
397ddde725dSArmin Le Grand                 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
3983aaca8a3SArmin Le Grand                 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
399025b0597SArmin Le Grand                 SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 0);
400ddde725dSArmin Le Grand 
401ddde725dSArmin Le Grand                 switch(aSVGToken)
402ddde725dSArmin Le Grand                 {
403ddde725dSArmin Le Grand                     /// valid tokens for which a new one was created
404ddde725dSArmin Le Grand 
405ddde725dSArmin Le Grand                     /// structural elements
406ddde725dSArmin Le Grand                     case SVGTokenDefs:
407ddde725dSArmin Le Grand                     case SVGTokenG:
408ddde725dSArmin Le Grand                     case SVGTokenSvg:
409ddde725dSArmin Le Grand                     case SVGTokenSymbol:
410ddde725dSArmin Le Grand                     case SVGTokenUse:
411ddde725dSArmin Le Grand 
412ddde725dSArmin Le Grand                     /// shape elements
413ddde725dSArmin Le Grand                     case SVGTokenCircle:
414ddde725dSArmin Le Grand                     case SVGTokenEllipse:
415ddde725dSArmin Le Grand                     case SVGTokenLine:
416ddde725dSArmin Le Grand                     case SVGTokenPath:
417ddde725dSArmin Le Grand                     case SVGTokenPolygon:
418ddde725dSArmin Le Grand                     case SVGTokenPolyline:
419ddde725dSArmin Le Grand                     case SVGTokenRect:
420ddde725dSArmin Le Grand                     case SVGTokenImage:
421ddde725dSArmin Le Grand 
422025b0597SArmin Le Grand                     /// title and description
423025b0597SArmin Le Grand                     case SVGTokenTitle:
424025b0597SArmin Le Grand                     case SVGTokenDesc:
425025b0597SArmin Le Grand 
426ddde725dSArmin Le Grand                     /// gradients
427ddde725dSArmin Le Grand                     case SVGTokenLinearGradient:
428ddde725dSArmin Le Grand                     case SVGTokenRadialGradient:
429ddde725dSArmin Le Grand 
430ddde725dSArmin Le Grand                     /// gradient stops
431ddde725dSArmin Le Grand                     case SVGTokenStop:
432ddde725dSArmin Le Grand 
433ddde725dSArmin Le Grand                     /// text
434ddde725dSArmin Le Grand                     case SVGTokenText:
435ddde725dSArmin Le Grand                     case SVGTokenTspan:
436ddde725dSArmin Le Grand                     case SVGTokenTextPath:
437ddde725dSArmin Le Grand                     case SVGTokenTref:
438ddde725dSArmin Le Grand 
439ddde725dSArmin Le Grand                     /// styles (as stylesheets)
440ddde725dSArmin Le Grand                     case SVGTokenStyle:
441ddde725dSArmin Le Grand 
442ddde725dSArmin Le Grand                     /// structural elements clip-path and mask
443ddde725dSArmin Le Grand                     case SVGTokenClipPathNode:
444ddde725dSArmin Le Grand                     case SVGTokenMask:
445ddde725dSArmin Le Grand 
446ddde725dSArmin Le Grand                     /// structural element marker
447ddde725dSArmin Le Grand                     case SVGTokenMarker:
448ddde725dSArmin Le Grand 
449ddde725dSArmin Le Grand                     /// structural element pattern
450ddde725dSArmin Le Grand                     case SVGTokenPattern:
451ddde725dSArmin Le Grand 
452ddde725dSArmin Le Grand                     /// content handling after parsing
453ddde725dSArmin Le Grand                     {
454ddde725dSArmin Le Grand                         if(mpTarget)
455ddde725dSArmin Le Grand                         {
456ddde725dSArmin Le Grand                             if(!mpTarget->getParent())
457ddde725dSArmin Le Grand                             {
458ddde725dSArmin Le Grand                                 // last element closing, save this tree
459ddde725dSArmin Le Grand                                 maDocument.appendNode(mpTarget);
460ddde725dSArmin Le Grand                             }
461ddde725dSArmin Le Grand 
462ddde725dSArmin Le Grand                             mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
463ddde725dSArmin Le Grand                         }
464ddde725dSArmin Le Grand                         else
465ddde725dSArmin Le Grand                         {
466ddde725dSArmin Le Grand                             OSL_ENSURE(false, "Closing token, but no context (!)");
467ddde725dSArmin Le Grand                         }
468ddde725dSArmin Le Grand                         break;
469ddde725dSArmin Le Grand                     }
470ddde725dSArmin Le Grand                     default:
471ddde725dSArmin Le Grand                     {
472ddde725dSArmin Le Grand                         /// invalid token, ignore
473ddde725dSArmin Le Grand                     }
474ddde725dSArmin Le Grand                 }
475ddde725dSArmin Le Grand 
476025b0597SArmin Le Grand                 if(pSvgTitleDescNode && mpTarget)
477025b0597SArmin Le Grand                 {
478025b0597SArmin Le Grand                     const rtl::OUString aText(pSvgTitleDescNode->getText());
479025b0597SArmin Le Grand 
480025b0597SArmin Le Grand                     if(aText.getLength())
481025b0597SArmin Le Grand                     {
482025b0597SArmin Le Grand                         if(SVGTokenTitle == aSVGToken)
483025b0597SArmin Le Grand                         {
484025b0597SArmin Le Grand                             mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText);
485025b0597SArmin Le Grand                         }
486025b0597SArmin Le Grand                         else // if(SVGTokenDesc == aSVGToken)
487025b0597SArmin Le Grand                         {
488025b0597SArmin Le Grand                             mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText);
489025b0597SArmin Le Grand                         }
490025b0597SArmin Le Grand                     }
491025b0597SArmin Le Grand                 }
492025b0597SArmin Le Grand 
4933aaca8a3SArmin Le Grand                 if(pCssStyle && pCssStyle->isTextCss())
4943aaca8a3SArmin Le Grand                 {
4953aaca8a3SArmin Le Grand                     // css style parsing
4963aaca8a3SArmin Le Grand                     if(maCssContents.size())
4973aaca8a3SArmin Le Grand                     {
4983aaca8a3SArmin Le Grand                         // need to interpret css styles and remember them as StyleSheets
4993aaca8a3SArmin Le Grand                         pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
5003aaca8a3SArmin Le Grand                         maCssContents.pop_back();
5013aaca8a3SArmin Le Grand                     }
5023aaca8a3SArmin Le Grand                     else
5033aaca8a3SArmin Le Grand                     {
5043aaca8a3SArmin Le Grand                         OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
5053aaca8a3SArmin Le Grand                     }
5063aaca8a3SArmin Le Grand                 }
5073aaca8a3SArmin Le Grand 
508ddde725dSArmin Le Grand                 if(pWhitespaceCheck)
509ddde725dSArmin Le Grand                 {
510ddde725dSArmin Le Grand                     // cleanup read strings
511ddde725dSArmin Le Grand                     whiteSpaceHandling(pWhitespaceCheck, 0);
512ddde725dSArmin Le Grand                 }
513ddde725dSArmin Le Grand             }
514ddde725dSArmin Le Grand         }
515ddde725dSArmin Le Grand 
516ddde725dSArmin Le Grand         void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
517ddde725dSArmin Le Grand         {
518025b0597SArmin Le Grand             const sal_uInt32 nLength(aChars.getLength());
519ddde725dSArmin Le Grand 
520025b0597SArmin Le Grand             if(mpTarget && nLength)
521025b0597SArmin Le Grand             {
522025b0597SArmin Le Grand                 switch(mpTarget->getType())
523ddde725dSArmin Le Grand                 {
524025b0597SArmin Le Grand                     case SVGTokenText:
525025b0597SArmin Le Grand                     case SVGTokenTspan:
526025b0597SArmin Le Grand                     case SVGTokenTextPath:
527ddde725dSArmin Le Grand                     {
528025b0597SArmin Le Grand                         const SvgNodeVector& rChilds = mpTarget->getChildren();
529025b0597SArmin Le Grand                         SvgCharacterNode* pTarget = 0;
530ddde725dSArmin Le Grand 
531025b0597SArmin Le Grand                         if(rChilds.size())
532025b0597SArmin Le Grand                         {
533025b0597SArmin Le Grand                             pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
534025b0597SArmin Le Grand                         }
535ddde725dSArmin Le Grand 
536025b0597SArmin Le Grand                         if(pTarget)
537025b0597SArmin Le Grand                         {
538025b0597SArmin Le Grand                             // concatenate to current character span
539025b0597SArmin Le Grand                             pTarget->concatenate(aChars);
540ddde725dSArmin Le Grand                         }
541025b0597SArmin Le Grand                         else
542ddde725dSArmin Le Grand                         {
543025b0597SArmin Le Grand                             // add character span as simplified tspan (no arguments)
544025b0597SArmin Le Grand                             // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
545025b0597SArmin Le Grand                             new SvgCharacterNode(maDocument, mpTarget, aChars);
546025b0597SArmin Le Grand                         }
547025b0597SArmin Le Grand                         break;
548025b0597SArmin Le Grand                     }
549025b0597SArmin Le Grand                     case SVGTokenStyle:
550025b0597SArmin Le Grand                     {
551025b0597SArmin Le Grand                         SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
552ddde725dSArmin Le Grand 
553025b0597SArmin Le Grand                         if(rSvgStyleNode.isTextCss())
554025b0597SArmin Le Grand                         {
555025b0597SArmin Le Grand                             // collect characters for css style
556025b0597SArmin Le Grand                             if(maCssContents.size())
557ddde725dSArmin Le Grand                             {
558025b0597SArmin Le Grand                                 const ::rtl::OUString aTrimmedChars(aChars.trim());
559ddde725dSArmin Le Grand 
560025b0597SArmin Le Grand                                 if(aTrimmedChars.getLength())
561ddde725dSArmin Le Grand                                 {
562025b0597SArmin Le Grand                                     std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1);
563025b0597SArmin Le Grand                                     (*aString) += aTrimmedChars;
564ddde725dSArmin Le Grand                                 }
565ddde725dSArmin Le Grand                             }
566025b0597SArmin Le Grand                             else
567025b0597SArmin Le Grand                             {
568025b0597SArmin Le Grand                                 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
569025b0597SArmin Le Grand                             }
570ddde725dSArmin Le Grand                         }
571025b0597SArmin Le Grand                         break;
572025b0597SArmin Le Grand                     }
573025b0597SArmin Le Grand                     case SVGTokenTitle:
574025b0597SArmin Le Grand                     case SVGTokenDesc:
575025b0597SArmin Le Grand                     {
576025b0597SArmin Le Grand                         SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget);
577025b0597SArmin Le Grand 
578025b0597SArmin Le Grand                         // add text directly to SvgTitleDescNode
579025b0597SArmin Le Grand                         rSvgTitleDescNode.concatenate(aChars);
580025b0597SArmin Le Grand                         break;
581025b0597SArmin Le Grand                     }
582025b0597SArmin Le Grand                     default:
583025b0597SArmin Le Grand                     {
584025b0597SArmin Le Grand                         // characters not used by a known node
585025b0597SArmin Le Grand                         break;
586ddde725dSArmin Le Grand                     }
587ddde725dSArmin Le Grand                 }
588ddde725dSArmin Le Grand             }
589ddde725dSArmin Le Grand         }
590ddde725dSArmin Le Grand 
591e2bf1e9dSArmin Le Grand         void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
592ddde725dSArmin Le Grand         {
593ddde725dSArmin Le Grand         }
594ddde725dSArmin Le Grand 
595e2bf1e9dSArmin Le Grand         void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
596ddde725dSArmin Le Grand         {
597ddde725dSArmin Le Grand         }
598ddde725dSArmin Le Grand 
599e2bf1e9dSArmin Le Grand         void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
600ddde725dSArmin Le Grand         {
601ddde725dSArmin Le Grand         }
602ddde725dSArmin Le Grand     } // end of namespace svgreader
603ddde725dSArmin Le Grand } // end of namespace svgio
604ddde725dSArmin Le Grand 
605ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
606ddde725dSArmin Le Grand // eof
607