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 {
whiteSpaceHandling(svgio::svgreader::SvgNode * pNode,svgio::svgreader::SvgCharacterNode * pLast)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     {
SvgDocHdl(const rtl::OUString & aAbsolutePath)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 
~SvgDocHdl()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 
startDocument()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 
endDocument()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 
startElement(const::rtl::OUString & aName,const uno::Reference<xml::sax::XAttributeList> & xAttribs)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             {
182ddde725dSArmin Le Grand                 const SVGToken aSVGToken(StrToSVGToken(aName));
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;
333*6549c64fSAndrea Pescetti                         const sal_uInt32 nAttributes(xAttribs->getLength());
334*6549c64fSAndrea Pescetti 
335*6549c64fSAndrea Pescetti                         if(0 == nAttributes)
336*6549c64fSAndrea Pescetti                         {
337*6549c64fSAndrea Pescetti                             // #125326# no attributes, thus also no type="text/css". This is allowed to be missing,
338*6549c64fSAndrea Pescetti                             // thus do mark this style as CssStyle. This is required to read the contained
339*6549c64fSAndrea Pescetti                             // text (which defines the css style)
340*6549c64fSAndrea Pescetti                             pNew->setTextCss(true);
341*6549c64fSAndrea Pescetti                         }
342*6549c64fSAndrea Pescetti                         else
343*6549c64fSAndrea Pescetti                         {
344*6549c64fSAndrea Pescetti                             // #125326# there are attributes, read them. This will set isTextCss to true if
345*6549c64fSAndrea Pescetti                             // a type="text/css" is contained as exact match, else not
346*6549c64fSAndrea Pescetti                             mpTarget->parseAttributes(xAttribs);
347*6549c64fSAndrea Pescetti                         }
3483aaca8a3SArmin Le Grand 
3493aaca8a3SArmin Le Grand                         if(pNew->isTextCss())
3503aaca8a3SArmin Le Grand                         {
351*6549c64fSAndrea Pescetti                             // if it is a Css style, allow reading text between the start and end tag (see
352*6549c64fSAndrea Pescetti                             // SvgDocHdl::characters for details)
3533aaca8a3SArmin Le Grand                             maCssContents.push_back(rtl::OUString());
3543aaca8a3SArmin Le Grand                         }
355ddde725dSArmin Le Grand                         break;
356ddde725dSArmin Le Grand                     }
357ddde725dSArmin Le Grand 
358ddde725dSArmin Le Grand                     /// structural elements clip-path and mask. Content gets scanned, but
359ddde725dSArmin Le Grand                     /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
360ddde725dSArmin Le Grand                     case SVGTokenClipPathNode:
361ddde725dSArmin Le Grand                     {
362ddde725dSArmin Le Grand                         /// new node for ClipPath
363ddde725dSArmin Le Grand                         mpTarget = new SvgClipPathNode(maDocument, mpTarget);
364ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
365ddde725dSArmin Le Grand                         break;
366ddde725dSArmin Le Grand                     }
367ddde725dSArmin Le Grand                     case SVGTokenMask:
368ddde725dSArmin Le Grand                     {
369ddde725dSArmin Le Grand                         /// new node for Mask
370ddde725dSArmin Le Grand                         mpTarget = new SvgMaskNode(maDocument, mpTarget);
371ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
372ddde725dSArmin Le Grand                         break;
373ddde725dSArmin Le Grand                     }
374ddde725dSArmin Le Grand 
375ddde725dSArmin Le Grand                     /// structural element marker
376ddde725dSArmin Le Grand                     case SVGTokenMarker:
377ddde725dSArmin Le Grand                     {
378ddde725dSArmin Le Grand                         /// new node for marker
379ddde725dSArmin Le Grand                         mpTarget = new SvgMarkerNode(maDocument, mpTarget);
380ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
381ddde725dSArmin Le Grand                         break;
382ddde725dSArmin Le Grand                     }
383ddde725dSArmin Le Grand 
384ddde725dSArmin Le Grand                     /// structural element pattern
385ddde725dSArmin Le Grand                     case SVGTokenPattern:
386ddde725dSArmin Le Grand                     {
387ddde725dSArmin Le Grand                         /// new node for pattern
388ddde725dSArmin Le Grand                         mpTarget = new SvgPatternNode(maDocument, mpTarget);
389ddde725dSArmin Le Grand                         mpTarget->parseAttributes(xAttribs);
390ddde725dSArmin Le Grand                         break;
391ddde725dSArmin Le Grand                     }
392ddde725dSArmin Le Grand 
393ddde725dSArmin Le Grand                     default:
394ddde725dSArmin Le Grand                     {
395ddde725dSArmin Le Grand                         /// invalid token, ignore
396ddde725dSArmin Le Grand #ifdef DBG_UTIL
397ddde725dSArmin Le Grand                         myAssert(
398ddde725dSArmin Le Grand                             rtl::OUString::createFromAscii("Unknown Base SvgToken <") +
399ddde725dSArmin Le Grand                             aName +
400ddde725dSArmin Le Grand                             rtl::OUString::createFromAscii("> (!)"));
401ddde725dSArmin Le Grand #endif
402ddde725dSArmin Le Grand                         break;
403ddde725dSArmin Le Grand                     }
404ddde725dSArmin Le Grand                 }
405ddde725dSArmin Le Grand             }
406ddde725dSArmin Le Grand         }
407ddde725dSArmin Le Grand 
endElement(const::rtl::OUString & aName)408ddde725dSArmin Le Grand         void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
409ddde725dSArmin Le Grand         {
410ddde725dSArmin Le Grand             if(aName.getLength())
411ddde725dSArmin Le Grand             {
412ddde725dSArmin Le Grand                 const SVGToken aSVGToken(StrToSVGToken(aName));
413ddde725dSArmin Le Grand                 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
4143aaca8a3SArmin Le Grand                 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
415025b0597SArmin Le Grand                 SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 0);
416ddde725dSArmin Le Grand 
417ddde725dSArmin Le Grand                 switch(aSVGToken)
418ddde725dSArmin Le Grand                 {
419ddde725dSArmin Le Grand                     /// valid tokens for which a new one was created
420ddde725dSArmin Le Grand 
421ddde725dSArmin Le Grand                     /// structural elements
422ddde725dSArmin Le Grand                     case SVGTokenDefs:
423ddde725dSArmin Le Grand                     case SVGTokenG:
424ddde725dSArmin Le Grand                     case SVGTokenSvg:
425ddde725dSArmin Le Grand                     case SVGTokenSymbol:
426ddde725dSArmin Le Grand                     case SVGTokenUse:
427ddde725dSArmin Le Grand 
428ddde725dSArmin Le Grand                     /// shape elements
429ddde725dSArmin Le Grand                     case SVGTokenCircle:
430ddde725dSArmin Le Grand                     case SVGTokenEllipse:
431ddde725dSArmin Le Grand                     case SVGTokenLine:
432ddde725dSArmin Le Grand                     case SVGTokenPath:
433ddde725dSArmin Le Grand                     case SVGTokenPolygon:
434ddde725dSArmin Le Grand                     case SVGTokenPolyline:
435ddde725dSArmin Le Grand                     case SVGTokenRect:
436ddde725dSArmin Le Grand                     case SVGTokenImage:
437ddde725dSArmin Le Grand 
438025b0597SArmin Le Grand                     /// title and description
439025b0597SArmin Le Grand                     case SVGTokenTitle:
440025b0597SArmin Le Grand                     case SVGTokenDesc:
441025b0597SArmin Le Grand 
442ddde725dSArmin Le Grand                     /// gradients
443ddde725dSArmin Le Grand                     case SVGTokenLinearGradient:
444ddde725dSArmin Le Grand                     case SVGTokenRadialGradient:
445ddde725dSArmin Le Grand 
446ddde725dSArmin Le Grand                     /// gradient stops
447ddde725dSArmin Le Grand                     case SVGTokenStop:
448ddde725dSArmin Le Grand 
449ddde725dSArmin Le Grand                     /// text
450ddde725dSArmin Le Grand                     case SVGTokenText:
451ddde725dSArmin Le Grand                     case SVGTokenTspan:
452ddde725dSArmin Le Grand                     case SVGTokenTextPath:
453ddde725dSArmin Le Grand                     case SVGTokenTref:
454ddde725dSArmin Le Grand 
455ddde725dSArmin Le Grand                     /// styles (as stylesheets)
456ddde725dSArmin Le Grand                     case SVGTokenStyle:
457ddde725dSArmin Le Grand 
458ddde725dSArmin Le Grand                     /// structural elements clip-path and mask
459ddde725dSArmin Le Grand                     case SVGTokenClipPathNode:
460ddde725dSArmin Le Grand                     case SVGTokenMask:
461ddde725dSArmin Le Grand 
462ddde725dSArmin Le Grand                     /// structural element marker
463ddde725dSArmin Le Grand                     case SVGTokenMarker:
464ddde725dSArmin Le Grand 
465ddde725dSArmin Le Grand                     /// structural element pattern
466ddde725dSArmin Le Grand                     case SVGTokenPattern:
467ddde725dSArmin Le Grand 
468ddde725dSArmin Le Grand                     /// content handling after parsing
469ddde725dSArmin Le Grand                     {
470ddde725dSArmin Le Grand                         if(mpTarget)
471ddde725dSArmin Le Grand                         {
472ddde725dSArmin Le Grand                             if(!mpTarget->getParent())
473ddde725dSArmin Le Grand                             {
474ddde725dSArmin Le Grand                                 // last element closing, save this tree
475ddde725dSArmin Le Grand                                 maDocument.appendNode(mpTarget);
476ddde725dSArmin Le Grand                             }
477ddde725dSArmin Le Grand 
478ddde725dSArmin Le Grand                             mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
479ddde725dSArmin Le Grand                         }
480ddde725dSArmin Le Grand                         else
481ddde725dSArmin Le Grand                         {
482ddde725dSArmin Le Grand                             OSL_ENSURE(false, "Closing token, but no context (!)");
483ddde725dSArmin Le Grand                         }
484ddde725dSArmin Le Grand                         break;
485ddde725dSArmin Le Grand                     }
486ddde725dSArmin Le Grand                     default:
487ddde725dSArmin Le Grand                     {
488ddde725dSArmin Le Grand                         /// invalid token, ignore
489ddde725dSArmin Le Grand                     }
490ddde725dSArmin Le Grand                 }
491ddde725dSArmin Le Grand 
492025b0597SArmin Le Grand                 if(pSvgTitleDescNode && mpTarget)
493025b0597SArmin Le Grand                 {
494025b0597SArmin Le Grand                     const rtl::OUString aText(pSvgTitleDescNode->getText());
495025b0597SArmin Le Grand 
496025b0597SArmin Le Grand                     if(aText.getLength())
497025b0597SArmin Le Grand                     {
498025b0597SArmin Le Grand                         if(SVGTokenTitle == aSVGToken)
499025b0597SArmin Le Grand                         {
500025b0597SArmin Le Grand                             mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText);
501025b0597SArmin Le Grand                         }
502025b0597SArmin Le Grand                         else // if(SVGTokenDesc == aSVGToken)
503025b0597SArmin Le Grand                         {
504025b0597SArmin Le Grand                             mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText);
505025b0597SArmin Le Grand                         }
506025b0597SArmin Le Grand                     }
507025b0597SArmin Le Grand                 }
508025b0597SArmin Le Grand 
5093aaca8a3SArmin Le Grand                 if(pCssStyle && pCssStyle->isTextCss())
5103aaca8a3SArmin Le Grand                 {
5113aaca8a3SArmin Le Grand                     // css style parsing
5123aaca8a3SArmin Le Grand                     if(maCssContents.size())
5133aaca8a3SArmin Le Grand                     {
5143aaca8a3SArmin Le Grand                         // need to interpret css styles and remember them as StyleSheets
5153aaca8a3SArmin Le Grand                         pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
5163aaca8a3SArmin Le Grand                         maCssContents.pop_back();
5173aaca8a3SArmin Le Grand                     }
5183aaca8a3SArmin Le Grand                     else
5193aaca8a3SArmin Le Grand                     {
5203aaca8a3SArmin Le Grand                         OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
5213aaca8a3SArmin Le Grand                     }
5223aaca8a3SArmin Le Grand                 }
5233aaca8a3SArmin Le Grand 
524ddde725dSArmin Le Grand                 if(pWhitespaceCheck)
525ddde725dSArmin Le Grand                 {
526ddde725dSArmin Le Grand                     // cleanup read strings
527ddde725dSArmin Le Grand                     whiteSpaceHandling(pWhitespaceCheck, 0);
528ddde725dSArmin Le Grand                 }
529ddde725dSArmin Le Grand             }
530ddde725dSArmin Le Grand         }
531ddde725dSArmin Le Grand 
characters(const::rtl::OUString & aChars)532ddde725dSArmin Le Grand         void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
533ddde725dSArmin Le Grand         {
534025b0597SArmin Le Grand             const sal_uInt32 nLength(aChars.getLength());
535ddde725dSArmin Le Grand 
536025b0597SArmin Le Grand             if(mpTarget && nLength)
537025b0597SArmin Le Grand             {
538025b0597SArmin Le Grand                 switch(mpTarget->getType())
539ddde725dSArmin Le Grand                 {
540025b0597SArmin Le Grand                     case SVGTokenText:
541025b0597SArmin Le Grand                     case SVGTokenTspan:
542025b0597SArmin Le Grand                     case SVGTokenTextPath:
543ddde725dSArmin Le Grand                     {
544025b0597SArmin Le Grand                         const SvgNodeVector& rChilds = mpTarget->getChildren();
545025b0597SArmin Le Grand                         SvgCharacterNode* pTarget = 0;
546ddde725dSArmin Le Grand 
547025b0597SArmin Le Grand                         if(rChilds.size())
548025b0597SArmin Le Grand                         {
549025b0597SArmin Le Grand                             pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
550025b0597SArmin Le Grand                         }
551ddde725dSArmin Le Grand 
552025b0597SArmin Le Grand                         if(pTarget)
553025b0597SArmin Le Grand                         {
554025b0597SArmin Le Grand                             // concatenate to current character span
555025b0597SArmin Le Grand                             pTarget->concatenate(aChars);
556ddde725dSArmin Le Grand                         }
557025b0597SArmin Le Grand                         else
558ddde725dSArmin Le Grand                         {
559025b0597SArmin Le Grand                             // add character span as simplified tspan (no arguments)
560025b0597SArmin Le Grand                             // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
561025b0597SArmin Le Grand                             new SvgCharacterNode(maDocument, mpTarget, aChars);
562025b0597SArmin Le Grand                         }
563025b0597SArmin Le Grand                         break;
564025b0597SArmin Le Grand                     }
565025b0597SArmin Le Grand                     case SVGTokenStyle:
566025b0597SArmin Le Grand                     {
567025b0597SArmin Le Grand                         SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
568ddde725dSArmin Le Grand 
569025b0597SArmin Le Grand                         if(rSvgStyleNode.isTextCss())
570025b0597SArmin Le Grand                         {
571025b0597SArmin Le Grand                             // collect characters for css style
572025b0597SArmin Le Grand                             if(maCssContents.size())
573ddde725dSArmin Le Grand                             {
574025b0597SArmin Le Grand                                 const ::rtl::OUString aTrimmedChars(aChars.trim());
575ddde725dSArmin Le Grand 
576025b0597SArmin Le Grand                                 if(aTrimmedChars.getLength())
577ddde725dSArmin Le Grand                                 {
578025b0597SArmin Le Grand                                     std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1);
579025b0597SArmin Le Grand                                     (*aString) += aTrimmedChars;
580ddde725dSArmin Le Grand                                 }
581ddde725dSArmin Le Grand                             }
582025b0597SArmin Le Grand                             else
583025b0597SArmin Le Grand                             {
584025b0597SArmin Le Grand                                 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
585025b0597SArmin Le Grand                             }
586ddde725dSArmin Le Grand                         }
587025b0597SArmin Le Grand                         break;
588025b0597SArmin Le Grand                     }
589025b0597SArmin Le Grand                     case SVGTokenTitle:
590025b0597SArmin Le Grand                     case SVGTokenDesc:
591025b0597SArmin Le Grand                     {
592025b0597SArmin Le Grand                         SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget);
593025b0597SArmin Le Grand 
594025b0597SArmin Le Grand                         // add text directly to SvgTitleDescNode
595025b0597SArmin Le Grand                         rSvgTitleDescNode.concatenate(aChars);
596025b0597SArmin Le Grand                         break;
597025b0597SArmin Le Grand                     }
598025b0597SArmin Le Grand                     default:
599025b0597SArmin Le Grand                     {
600025b0597SArmin Le Grand                         // characters not used by a known node
601025b0597SArmin Le Grand                         break;
602ddde725dSArmin Le Grand                     }
603ddde725dSArmin Le Grand                 }
604ddde725dSArmin Le Grand             }
605ddde725dSArmin Le Grand         }
606ddde725dSArmin Le Grand 
ignorableWhitespace(const::rtl::OUString &)607e2bf1e9dSArmin Le Grand         void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
608ddde725dSArmin Le Grand         {
609ddde725dSArmin Le Grand         }
610ddde725dSArmin Le Grand 
processingInstruction(const::rtl::OUString &,const::rtl::OUString &)611e2bf1e9dSArmin Le Grand         void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
612ddde725dSArmin Le Grand         {
613ddde725dSArmin Le Grand         }
614ddde725dSArmin Le Grand 
setDocumentLocator(const uno::Reference<xml::sax::XLocator> &)615e2bf1e9dSArmin Le Grand         void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
616ddde725dSArmin Le Grand         {
617ddde725dSArmin Le Grand         }
618ddde725dSArmin Le Grand     } // end of namespace svgreader
619ddde725dSArmin Le Grand } // end of namespace svgio
620ddde725dSArmin Le Grand 
621ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
622ddde725dSArmin Le Grand // eof
623