1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
23*b1cdbd2cSJim Jagielski #include "precompiled_svgio.hxx"
24*b1cdbd2cSJim Jagielski 
25*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgdocumenthandler.hxx>
26*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtoken.hxx>
27*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgsvgnode.hxx>
28*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svggnode.hxx>
29*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgnode.hxx>
30*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgpathnode.hxx>
31*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgrectnode.hxx>
32*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svggradientnode.hxx>
33*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svggradientstopnode.hxx>
34*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgsymbolnode.hxx>
35*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgusenode.hxx>
36*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgcirclenode.hxx>
37*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgellipsenode.hxx>
38*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svglinenode.hxx>
39*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgpolynode.hxx>
40*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgsymbolnode.hxx>
41*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtextnode.hxx>
42*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgcharacternode.hxx>
43*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtspannode.hxx>
44*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtrefnode.hxx>
45*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtextpathnode.hxx>
46*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgstylenode.hxx>
47*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgimagenode.hxx>
48*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgclippathnode.hxx>
49*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgmasknode.hxx>
50*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgmarkernode.hxx>
51*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgpatternnode.hxx>
52*b1cdbd2cSJim Jagielski #include <svgio/svgreader/svgtitledescnode.hxx>
53*b1cdbd2cSJim Jagielski 
54*b1cdbd2cSJim Jagielski //////////////////////////////////////////////////////////////////////////////
55*b1cdbd2cSJim Jagielski 
56*b1cdbd2cSJim Jagielski using namespace com::sun::star;
57*b1cdbd2cSJim Jagielski 
58*b1cdbd2cSJim Jagielski //////////////////////////////////////////////////////////////////////////////
59*b1cdbd2cSJim Jagielski 
60*b1cdbd2cSJim Jagielski namespace
61*b1cdbd2cSJim Jagielski {
whiteSpaceHandling(svgio::svgreader::SvgNode * pNode,svgio::svgreader::SvgCharacterNode * pLast)62*b1cdbd2cSJim Jagielski     svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast)
63*b1cdbd2cSJim Jagielski     {
64*b1cdbd2cSJim Jagielski         if(pNode)
65*b1cdbd2cSJim Jagielski         {
66*b1cdbd2cSJim Jagielski             const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren();
67*b1cdbd2cSJim Jagielski             const sal_uInt32 nCount(rChilds.size());
68*b1cdbd2cSJim Jagielski 
69*b1cdbd2cSJim Jagielski             for(sal_uInt32 a(0); a < nCount; a++)
70*b1cdbd2cSJim Jagielski             {
71*b1cdbd2cSJim Jagielski                 svgio::svgreader::SvgNode* pCandidate = rChilds[a];
72*b1cdbd2cSJim Jagielski 
73*b1cdbd2cSJim Jagielski                 if(pCandidate)
74*b1cdbd2cSJim Jagielski                 {
75*b1cdbd2cSJim Jagielski                     switch(pCandidate->getType())
76*b1cdbd2cSJim Jagielski                     {
77*b1cdbd2cSJim Jagielski                         case svgio::svgreader::SVGTokenCharacter:
78*b1cdbd2cSJim Jagielski                         {
79*b1cdbd2cSJim Jagielski                             // clean whitespace in text span
80*b1cdbd2cSJim Jagielski                             svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate);
81*b1cdbd2cSJim Jagielski                             pCharNode->whiteSpaceHandling();
82*b1cdbd2cSJim Jagielski 
83*b1cdbd2cSJim Jagielski                             // pCharNode may have lost all text. If that's the case, ignore
84*b1cdbd2cSJim Jagielski                             // as invalid character node
85*b1cdbd2cSJim Jagielski                             if(pCharNode->getText().getLength())
86*b1cdbd2cSJim Jagielski                             {
87*b1cdbd2cSJim Jagielski                                 if(pLast)
88*b1cdbd2cSJim Jagielski                                 {
89*b1cdbd2cSJim Jagielski                                     bool bAddGap(true);
90*b1cdbd2cSJim Jagielski                                     static bool bNoGapsForBaselineShift(true);
91*b1cdbd2cSJim Jagielski 
92*b1cdbd2cSJim Jagielski                                     if(bNoGapsForBaselineShift)
93*b1cdbd2cSJim Jagielski                                     {
94*b1cdbd2cSJim Jagielski                                         // With this option a baseline shift between two char parts ('words')
95*b1cdbd2cSJim Jagielski                                         // will not add a space 'gap' to the end of the (non-last) word. This
96*b1cdbd2cSJim Jagielski                                         // seems to be the standard behaviour, see last bugdoc attached #122524#
97*b1cdbd2cSJim Jagielski                                         const svgio::svgreader::SvgStyleAttributes* pStyleLast = pLast->getSvgStyleAttributes();
98*b1cdbd2cSJim Jagielski                                         const svgio::svgreader::SvgStyleAttributes* pStyleCurrent = pCandidate->getSvgStyleAttributes();
99*b1cdbd2cSJim Jagielski 
100*b1cdbd2cSJim Jagielski                                         if(pStyleLast && pStyleCurrent && pStyleLast->getBaselineShift() != pStyleCurrent->getBaselineShift())
101*b1cdbd2cSJim Jagielski                                         {
102*b1cdbd2cSJim Jagielski                                             bAddGap = false;
103*b1cdbd2cSJim Jagielski                                         }
104*b1cdbd2cSJim Jagielski                                     }
105*b1cdbd2cSJim Jagielski 
106*b1cdbd2cSJim Jagielski                                     // add in-between whitespace (single space) to last
107*b1cdbd2cSJim Jagielski                                     // known character node
108*b1cdbd2cSJim Jagielski                                     if(bAddGap)
109*b1cdbd2cSJim Jagielski                                     {
110*b1cdbd2cSJim Jagielski                                         pLast->addGap();
111*b1cdbd2cSJim Jagielski                                     }
112*b1cdbd2cSJim Jagielski                                 }
113*b1cdbd2cSJim Jagielski 
114*b1cdbd2cSJim Jagielski                                 // remember new last corected character node
115*b1cdbd2cSJim Jagielski                                 pLast = pCharNode;
116*b1cdbd2cSJim Jagielski                             }
117*b1cdbd2cSJim Jagielski                             break;
118*b1cdbd2cSJim Jagielski                         }
119*b1cdbd2cSJim Jagielski                         case svgio::svgreader::SVGTokenTspan:
120*b1cdbd2cSJim Jagielski                         case svgio::svgreader::SVGTokenTextPath:
121*b1cdbd2cSJim Jagielski                         case svgio::svgreader::SVGTokenTref:
122*b1cdbd2cSJim Jagielski                         {
123*b1cdbd2cSJim Jagielski                             // recursively clean whitespaces in subhierarchy
124*b1cdbd2cSJim Jagielski                             pLast = whiteSpaceHandling(pCandidate, pLast);
125*b1cdbd2cSJim Jagielski                             break;
126*b1cdbd2cSJim Jagielski                         }
127*b1cdbd2cSJim Jagielski                         default:
128*b1cdbd2cSJim Jagielski                         {
129*b1cdbd2cSJim Jagielski                             OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)");
130*b1cdbd2cSJim Jagielski                             break;
131*b1cdbd2cSJim Jagielski                         }
132*b1cdbd2cSJim Jagielski                     }
133*b1cdbd2cSJim Jagielski                 }
134*b1cdbd2cSJim Jagielski             }
135*b1cdbd2cSJim Jagielski         }
136*b1cdbd2cSJim Jagielski 
137*b1cdbd2cSJim Jagielski         return pLast;
138*b1cdbd2cSJim Jagielski     }
139*b1cdbd2cSJim Jagielski }
140*b1cdbd2cSJim Jagielski 
141*b1cdbd2cSJim Jagielski //////////////////////////////////////////////////////////////////////////////
142*b1cdbd2cSJim Jagielski 
143*b1cdbd2cSJim Jagielski namespace svgio
144*b1cdbd2cSJim Jagielski {
145*b1cdbd2cSJim Jagielski     namespace svgreader
146*b1cdbd2cSJim Jagielski     {
SvgDocHdl(const rtl::OUString & aAbsolutePath)147*b1cdbd2cSJim Jagielski         SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath)
148*b1cdbd2cSJim Jagielski         :   maDocument(aAbsolutePath),
149*b1cdbd2cSJim Jagielski             mpTarget(0),
150*b1cdbd2cSJim Jagielski             maCssContents()
151*b1cdbd2cSJim Jagielski         {
152*b1cdbd2cSJim Jagielski         }
153*b1cdbd2cSJim Jagielski 
~SvgDocHdl()154*b1cdbd2cSJim Jagielski         SvgDocHdl::~SvgDocHdl()
155*b1cdbd2cSJim Jagielski         {
156*b1cdbd2cSJim Jagielski #ifdef DBG_UTIL
157*b1cdbd2cSJim Jagielski             if(mpTarget)
158*b1cdbd2cSJim Jagielski             {
159*b1cdbd2cSJim Jagielski                 OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)");
160*b1cdbd2cSJim Jagielski                 delete mpTarget;
161*b1cdbd2cSJim Jagielski             }
162*b1cdbd2cSJim Jagielski             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)");
163*b1cdbd2cSJim Jagielski #endif
164*b1cdbd2cSJim Jagielski         }
165*b1cdbd2cSJim Jagielski 
startDocument()166*b1cdbd2cSJim Jagielski         void SvgDocHdl::startDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
167*b1cdbd2cSJim Jagielski         {
168*b1cdbd2cSJim Jagielski             OSL_ENSURE(!mpTarget, "Already a target at document start (!)");
169*b1cdbd2cSJim Jagielski             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)");
170*b1cdbd2cSJim Jagielski         }
171*b1cdbd2cSJim Jagielski 
endDocument()172*b1cdbd2cSJim Jagielski         void SvgDocHdl::endDocument(  ) throw (xml::sax::SAXException, uno::RuntimeException)
173*b1cdbd2cSJim Jagielski         {
174*b1cdbd2cSJim Jagielski             OSL_ENSURE(!mpTarget, "Still a target at document end (!)");
175*b1cdbd2cSJim Jagielski             OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)");
176*b1cdbd2cSJim Jagielski         }
177*b1cdbd2cSJim Jagielski 
startElement(const::rtl::OUString & aName,const uno::Reference<xml::sax::XAttributeList> & xAttribs)178*b1cdbd2cSJim Jagielski         void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException)
179*b1cdbd2cSJim Jagielski         {
180*b1cdbd2cSJim Jagielski             if(aName.getLength())
181*b1cdbd2cSJim Jagielski             {
182*b1cdbd2cSJim Jagielski                 const SVGToken aSVGToken(StrToSVGToken(aName));
183*b1cdbd2cSJim Jagielski 
184*b1cdbd2cSJim Jagielski                 switch(aSVGToken)
185*b1cdbd2cSJim Jagielski                 {
186*b1cdbd2cSJim Jagielski                     /// structural elements
187*b1cdbd2cSJim Jagielski                     case SVGTokenSymbol:
188*b1cdbd2cSJim Jagielski                     {
189*b1cdbd2cSJim Jagielski                         /// new basic node for Symbol. Content gets scanned, but
190*b1cdbd2cSJim Jagielski                         /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
191*b1cdbd2cSJim Jagielski                         mpTarget = new SvgSymbolNode(maDocument, mpTarget);
192*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
193*b1cdbd2cSJim Jagielski                         break;
194*b1cdbd2cSJim Jagielski                     }
195*b1cdbd2cSJim Jagielski                     case SVGTokenDefs:
196*b1cdbd2cSJim Jagielski                     case SVGTokenG:
197*b1cdbd2cSJim Jagielski                     {
198*b1cdbd2cSJim Jagielski                         /// new node for Defs/G
199*b1cdbd2cSJim Jagielski                         mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget);
200*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
201*b1cdbd2cSJim Jagielski                         break;
202*b1cdbd2cSJim Jagielski                     }
203*b1cdbd2cSJim Jagielski                     case SVGTokenSvg:
204*b1cdbd2cSJim Jagielski                     {
205*b1cdbd2cSJim Jagielski                         /// new node for Svg
206*b1cdbd2cSJim Jagielski                         mpTarget = new SvgSvgNode(maDocument, mpTarget);
207*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
208*b1cdbd2cSJim Jagielski                         break;
209*b1cdbd2cSJim Jagielski                     }
210*b1cdbd2cSJim Jagielski                     case SVGTokenUse:
211*b1cdbd2cSJim Jagielski                     {
212*b1cdbd2cSJim Jagielski                         /// new node for Use
213*b1cdbd2cSJim Jagielski                         mpTarget = new SvgUseNode(maDocument, mpTarget);
214*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
215*b1cdbd2cSJim Jagielski                         break;
216*b1cdbd2cSJim Jagielski                     }
217*b1cdbd2cSJim Jagielski 
218*b1cdbd2cSJim Jagielski                     /// shape elements
219*b1cdbd2cSJim Jagielski                     case SVGTokenCircle:
220*b1cdbd2cSJim Jagielski                     {
221*b1cdbd2cSJim Jagielski                         /// new node for Circle
222*b1cdbd2cSJim Jagielski                         mpTarget = new SvgCircleNode(maDocument, mpTarget);
223*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
224*b1cdbd2cSJim Jagielski                         break;
225*b1cdbd2cSJim Jagielski                     }
226*b1cdbd2cSJim Jagielski                     case SVGTokenEllipse:
227*b1cdbd2cSJim Jagielski                     {
228*b1cdbd2cSJim Jagielski                         /// new node for Ellipse
229*b1cdbd2cSJim Jagielski                         mpTarget = new SvgEllipseNode(maDocument, mpTarget);
230*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
231*b1cdbd2cSJim Jagielski                         break;
232*b1cdbd2cSJim Jagielski                     }
233*b1cdbd2cSJim Jagielski                     case SVGTokenLine:
234*b1cdbd2cSJim Jagielski                     {
235*b1cdbd2cSJim Jagielski                         /// new node for Line
236*b1cdbd2cSJim Jagielski                         mpTarget = new SvgLineNode(maDocument, mpTarget);
237*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
238*b1cdbd2cSJim Jagielski                         break;
239*b1cdbd2cSJim Jagielski                     }
240*b1cdbd2cSJim Jagielski                     case SVGTokenPath:
241*b1cdbd2cSJim Jagielski                     {
242*b1cdbd2cSJim Jagielski                         /// new node for Path
243*b1cdbd2cSJim Jagielski                         mpTarget = new SvgPathNode(maDocument, mpTarget);
244*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
245*b1cdbd2cSJim Jagielski                         break;
246*b1cdbd2cSJim Jagielski                     }
247*b1cdbd2cSJim Jagielski                     case SVGTokenPolygon:
248*b1cdbd2cSJim Jagielski                     {
249*b1cdbd2cSJim Jagielski                         /// new node for Polygon
250*b1cdbd2cSJim Jagielski                         mpTarget = new SvgPolyNode(maDocument, mpTarget, false);
251*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
252*b1cdbd2cSJim Jagielski                         break;
253*b1cdbd2cSJim Jagielski                     }
254*b1cdbd2cSJim Jagielski                     case SVGTokenPolyline:
255*b1cdbd2cSJim Jagielski                     {
256*b1cdbd2cSJim Jagielski                         /// new node for Polyline
257*b1cdbd2cSJim Jagielski                         mpTarget = new SvgPolyNode(maDocument, mpTarget, true);
258*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
259*b1cdbd2cSJim Jagielski                         break;
260*b1cdbd2cSJim Jagielski                     }
261*b1cdbd2cSJim Jagielski                     case SVGTokenRect:
262*b1cdbd2cSJim Jagielski                     {
263*b1cdbd2cSJim Jagielski                         /// new node for Rect
264*b1cdbd2cSJim Jagielski                         mpTarget = new SvgRectNode(maDocument, mpTarget);
265*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
266*b1cdbd2cSJim Jagielski                         break;
267*b1cdbd2cSJim Jagielski                     }
268*b1cdbd2cSJim Jagielski                     case SVGTokenImage:
269*b1cdbd2cSJim Jagielski                     {
270*b1cdbd2cSJim Jagielski                         /// new node for Image
271*b1cdbd2cSJim Jagielski                         mpTarget = new SvgImageNode(maDocument, mpTarget);
272*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
273*b1cdbd2cSJim Jagielski                         break;
274*b1cdbd2cSJim Jagielski                     }
275*b1cdbd2cSJim Jagielski 
276*b1cdbd2cSJim Jagielski                     /// title and description
277*b1cdbd2cSJim Jagielski                     case SVGTokenTitle:
278*b1cdbd2cSJim Jagielski                     case SVGTokenDesc:
279*b1cdbd2cSJim Jagielski                     {
280*b1cdbd2cSJim Jagielski                         /// new node for Title and/or Desc
281*b1cdbd2cSJim Jagielski                         mpTarget = new SvgTitleDescNode(aSVGToken, maDocument, mpTarget);
282*b1cdbd2cSJim Jagielski                         break;
283*b1cdbd2cSJim Jagielski                     }
284*b1cdbd2cSJim Jagielski 
285*b1cdbd2cSJim Jagielski                     /// gradients
286*b1cdbd2cSJim Jagielski                     case SVGTokenLinearGradient:
287*b1cdbd2cSJim Jagielski                     case SVGTokenRadialGradient:
288*b1cdbd2cSJim Jagielski                     {
289*b1cdbd2cSJim Jagielski                         mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget);
290*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
291*b1cdbd2cSJim Jagielski                         break;
292*b1cdbd2cSJim Jagielski                     }
293*b1cdbd2cSJim Jagielski 
294*b1cdbd2cSJim Jagielski                     /// gradient stops
295*b1cdbd2cSJim Jagielski                     case SVGTokenStop:
296*b1cdbd2cSJim Jagielski                     {
297*b1cdbd2cSJim Jagielski                         mpTarget = new SvgGradientStopNode(maDocument, mpTarget);
298*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
299*b1cdbd2cSJim Jagielski                         break;
300*b1cdbd2cSJim Jagielski                     }
301*b1cdbd2cSJim Jagielski 
302*b1cdbd2cSJim Jagielski                     /// text
303*b1cdbd2cSJim Jagielski                     case SVGTokenText:
304*b1cdbd2cSJim Jagielski                     {
305*b1cdbd2cSJim Jagielski                         mpTarget = new SvgTextNode(maDocument, mpTarget);
306*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
307*b1cdbd2cSJim Jagielski                         break;
308*b1cdbd2cSJim Jagielski                     }
309*b1cdbd2cSJim Jagielski                     case SVGTokenTspan:
310*b1cdbd2cSJim Jagielski                     {
311*b1cdbd2cSJim Jagielski                         mpTarget = new SvgTspanNode(maDocument, mpTarget);
312*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
313*b1cdbd2cSJim Jagielski                         break;
314*b1cdbd2cSJim Jagielski                     }
315*b1cdbd2cSJim Jagielski                     case SVGTokenTref:
316*b1cdbd2cSJim Jagielski                     {
317*b1cdbd2cSJim Jagielski                         mpTarget = new SvgTrefNode(maDocument, mpTarget);
318*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
319*b1cdbd2cSJim Jagielski                         break;
320*b1cdbd2cSJim Jagielski                     }
321*b1cdbd2cSJim Jagielski                     case SVGTokenTextPath:
322*b1cdbd2cSJim Jagielski                     {
323*b1cdbd2cSJim Jagielski                         mpTarget = new SvgTextPathNode(maDocument, mpTarget);
324*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
325*b1cdbd2cSJim Jagielski                         break;
326*b1cdbd2cSJim Jagielski                     }
327*b1cdbd2cSJim Jagielski 
328*b1cdbd2cSJim Jagielski                     /// styles (as stylesheets)
329*b1cdbd2cSJim Jagielski                     case SVGTokenStyle:
330*b1cdbd2cSJim Jagielski                     {
331*b1cdbd2cSJim Jagielski                         SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget);
332*b1cdbd2cSJim Jagielski                         mpTarget = pNew;
333*b1cdbd2cSJim Jagielski                         const sal_uInt32 nAttributes(xAttribs->getLength());
334*b1cdbd2cSJim Jagielski 
335*b1cdbd2cSJim Jagielski                         if(0 == nAttributes)
336*b1cdbd2cSJim Jagielski                         {
337*b1cdbd2cSJim Jagielski                             // #125326# no attributes, thus also no type="text/css". This is allowed to be missing,
338*b1cdbd2cSJim Jagielski                             // thus do mark this style as CssStyle. This is required to read the contained
339*b1cdbd2cSJim Jagielski                             // text (which defines the css style)
340*b1cdbd2cSJim Jagielski                             pNew->setTextCss(true);
341*b1cdbd2cSJim Jagielski                         }
342*b1cdbd2cSJim Jagielski                         else
343*b1cdbd2cSJim Jagielski                         {
344*b1cdbd2cSJim Jagielski                             // #125326# there are attributes, read them. This will set isTextCss to true if
345*b1cdbd2cSJim Jagielski                             // a type="text/css" is contained as exact match, else not
346*b1cdbd2cSJim Jagielski                             mpTarget->parseAttributes(xAttribs);
347*b1cdbd2cSJim Jagielski                         }
348*b1cdbd2cSJim Jagielski 
349*b1cdbd2cSJim Jagielski                         if(pNew->isTextCss())
350*b1cdbd2cSJim Jagielski                         {
351*b1cdbd2cSJim Jagielski                             // if it is a Css style, allow reading text between the start and end tag (see
352*b1cdbd2cSJim Jagielski                             // SvgDocHdl::characters for details)
353*b1cdbd2cSJim Jagielski                             maCssContents.push_back(rtl::OUString());
354*b1cdbd2cSJim Jagielski                         }
355*b1cdbd2cSJim Jagielski                         break;
356*b1cdbd2cSJim Jagielski                     }
357*b1cdbd2cSJim Jagielski 
358*b1cdbd2cSJim Jagielski                     /// structural elements clip-path and mask. Content gets scanned, but
359*b1cdbd2cSJim Jagielski                     /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced)
360*b1cdbd2cSJim Jagielski                     case SVGTokenClipPathNode:
361*b1cdbd2cSJim Jagielski                     {
362*b1cdbd2cSJim Jagielski                         /// new node for ClipPath
363*b1cdbd2cSJim Jagielski                         mpTarget = new SvgClipPathNode(maDocument, mpTarget);
364*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
365*b1cdbd2cSJim Jagielski                         break;
366*b1cdbd2cSJim Jagielski                     }
367*b1cdbd2cSJim Jagielski                     case SVGTokenMask:
368*b1cdbd2cSJim Jagielski                     {
369*b1cdbd2cSJim Jagielski                         /// new node for Mask
370*b1cdbd2cSJim Jagielski                         mpTarget = new SvgMaskNode(maDocument, mpTarget);
371*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
372*b1cdbd2cSJim Jagielski                         break;
373*b1cdbd2cSJim Jagielski                     }
374*b1cdbd2cSJim Jagielski 
375*b1cdbd2cSJim Jagielski                     /// structural element marker
376*b1cdbd2cSJim Jagielski                     case SVGTokenMarker:
377*b1cdbd2cSJim Jagielski                     {
378*b1cdbd2cSJim Jagielski                         /// new node for marker
379*b1cdbd2cSJim Jagielski                         mpTarget = new SvgMarkerNode(maDocument, mpTarget);
380*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
381*b1cdbd2cSJim Jagielski                         break;
382*b1cdbd2cSJim Jagielski                     }
383*b1cdbd2cSJim Jagielski 
384*b1cdbd2cSJim Jagielski                     /// structural element pattern
385*b1cdbd2cSJim Jagielski                     case SVGTokenPattern:
386*b1cdbd2cSJim Jagielski                     {
387*b1cdbd2cSJim Jagielski                         /// new node for pattern
388*b1cdbd2cSJim Jagielski                         mpTarget = new SvgPatternNode(maDocument, mpTarget);
389*b1cdbd2cSJim Jagielski                         mpTarget->parseAttributes(xAttribs);
390*b1cdbd2cSJim Jagielski                         break;
391*b1cdbd2cSJim Jagielski                     }
392*b1cdbd2cSJim Jagielski 
393*b1cdbd2cSJim Jagielski                     default:
394*b1cdbd2cSJim Jagielski                     {
395*b1cdbd2cSJim Jagielski                         /// invalid token, ignore
396*b1cdbd2cSJim Jagielski #ifdef DBG_UTIL
397*b1cdbd2cSJim Jagielski                         myAssert(
398*b1cdbd2cSJim Jagielski                             rtl::OUString::createFromAscii("Unknown Base SvgToken <") +
399*b1cdbd2cSJim Jagielski                             aName +
400*b1cdbd2cSJim Jagielski                             rtl::OUString::createFromAscii("> (!)"));
401*b1cdbd2cSJim Jagielski #endif
402*b1cdbd2cSJim Jagielski                         break;
403*b1cdbd2cSJim Jagielski                     }
404*b1cdbd2cSJim Jagielski                 }
405*b1cdbd2cSJim Jagielski             }
406*b1cdbd2cSJim Jagielski         }
407*b1cdbd2cSJim Jagielski 
endElement(const::rtl::OUString & aName)408*b1cdbd2cSJim Jagielski         void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException)
409*b1cdbd2cSJim Jagielski         {
410*b1cdbd2cSJim Jagielski             if(aName.getLength())
411*b1cdbd2cSJim Jagielski             {
412*b1cdbd2cSJim Jagielski                 const SVGToken aSVGToken(StrToSVGToken(aName));
413*b1cdbd2cSJim Jagielski                 SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0);
414*b1cdbd2cSJim Jagielski                 SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0);
415*b1cdbd2cSJim Jagielski                 SvgTitleDescNode* pSvgTitleDescNode(SVGTokenTitle == aSVGToken || SVGTokenDesc == aSVGToken ? static_cast< SvgTitleDescNode* >(mpTarget) : 0);
416*b1cdbd2cSJim Jagielski 
417*b1cdbd2cSJim Jagielski                 switch(aSVGToken)
418*b1cdbd2cSJim Jagielski                 {
419*b1cdbd2cSJim Jagielski                     /// valid tokens for which a new one was created
420*b1cdbd2cSJim Jagielski 
421*b1cdbd2cSJim Jagielski                     /// structural elements
422*b1cdbd2cSJim Jagielski                     case SVGTokenDefs:
423*b1cdbd2cSJim Jagielski                     case SVGTokenG:
424*b1cdbd2cSJim Jagielski                     case SVGTokenSvg:
425*b1cdbd2cSJim Jagielski                     case SVGTokenSymbol:
426*b1cdbd2cSJim Jagielski                     case SVGTokenUse:
427*b1cdbd2cSJim Jagielski 
428*b1cdbd2cSJim Jagielski                     /// shape elements
429*b1cdbd2cSJim Jagielski                     case SVGTokenCircle:
430*b1cdbd2cSJim Jagielski                     case SVGTokenEllipse:
431*b1cdbd2cSJim Jagielski                     case SVGTokenLine:
432*b1cdbd2cSJim Jagielski                     case SVGTokenPath:
433*b1cdbd2cSJim Jagielski                     case SVGTokenPolygon:
434*b1cdbd2cSJim Jagielski                     case SVGTokenPolyline:
435*b1cdbd2cSJim Jagielski                     case SVGTokenRect:
436*b1cdbd2cSJim Jagielski                     case SVGTokenImage:
437*b1cdbd2cSJim Jagielski 
438*b1cdbd2cSJim Jagielski                     /// title and description
439*b1cdbd2cSJim Jagielski                     case SVGTokenTitle:
440*b1cdbd2cSJim Jagielski                     case SVGTokenDesc:
441*b1cdbd2cSJim Jagielski 
442*b1cdbd2cSJim Jagielski                     /// gradients
443*b1cdbd2cSJim Jagielski                     case SVGTokenLinearGradient:
444*b1cdbd2cSJim Jagielski                     case SVGTokenRadialGradient:
445*b1cdbd2cSJim Jagielski 
446*b1cdbd2cSJim Jagielski                     /// gradient stops
447*b1cdbd2cSJim Jagielski                     case SVGTokenStop:
448*b1cdbd2cSJim Jagielski 
449*b1cdbd2cSJim Jagielski                     /// text
450*b1cdbd2cSJim Jagielski                     case SVGTokenText:
451*b1cdbd2cSJim Jagielski                     case SVGTokenTspan:
452*b1cdbd2cSJim Jagielski                     case SVGTokenTextPath:
453*b1cdbd2cSJim Jagielski                     case SVGTokenTref:
454*b1cdbd2cSJim Jagielski 
455*b1cdbd2cSJim Jagielski                     /// styles (as stylesheets)
456*b1cdbd2cSJim Jagielski                     case SVGTokenStyle:
457*b1cdbd2cSJim Jagielski 
458*b1cdbd2cSJim Jagielski                     /// structural elements clip-path and mask
459*b1cdbd2cSJim Jagielski                     case SVGTokenClipPathNode:
460*b1cdbd2cSJim Jagielski                     case SVGTokenMask:
461*b1cdbd2cSJim Jagielski 
462*b1cdbd2cSJim Jagielski                     /// structural element marker
463*b1cdbd2cSJim Jagielski                     case SVGTokenMarker:
464*b1cdbd2cSJim Jagielski 
465*b1cdbd2cSJim Jagielski                     /// structural element pattern
466*b1cdbd2cSJim Jagielski                     case SVGTokenPattern:
467*b1cdbd2cSJim Jagielski 
468*b1cdbd2cSJim Jagielski                     /// content handling after parsing
469*b1cdbd2cSJim Jagielski                     {
470*b1cdbd2cSJim Jagielski                         if(mpTarget)
471*b1cdbd2cSJim Jagielski                         {
472*b1cdbd2cSJim Jagielski                             if(!mpTarget->getParent())
473*b1cdbd2cSJim Jagielski                             {
474*b1cdbd2cSJim Jagielski                                 // last element closing, save this tree
475*b1cdbd2cSJim Jagielski                                 maDocument.appendNode(mpTarget);
476*b1cdbd2cSJim Jagielski                             }
477*b1cdbd2cSJim Jagielski 
478*b1cdbd2cSJim Jagielski                             mpTarget = const_cast< SvgNode* >(mpTarget->getParent());
479*b1cdbd2cSJim Jagielski                         }
480*b1cdbd2cSJim Jagielski                         else
481*b1cdbd2cSJim Jagielski                         {
482*b1cdbd2cSJim Jagielski                             OSL_ENSURE(false, "Closing token, but no context (!)");
483*b1cdbd2cSJim Jagielski                         }
484*b1cdbd2cSJim Jagielski                         break;
485*b1cdbd2cSJim Jagielski                     }
486*b1cdbd2cSJim Jagielski                     default:
487*b1cdbd2cSJim Jagielski                     {
488*b1cdbd2cSJim Jagielski                         /// invalid token, ignore
489*b1cdbd2cSJim Jagielski                     }
490*b1cdbd2cSJim Jagielski                 }
491*b1cdbd2cSJim Jagielski 
492*b1cdbd2cSJim Jagielski                 if(pSvgTitleDescNode && mpTarget)
493*b1cdbd2cSJim Jagielski                 {
494*b1cdbd2cSJim Jagielski                     const rtl::OUString aText(pSvgTitleDescNode->getText());
495*b1cdbd2cSJim Jagielski 
496*b1cdbd2cSJim Jagielski                     if(aText.getLength())
497*b1cdbd2cSJim Jagielski                     {
498*b1cdbd2cSJim Jagielski                         if(SVGTokenTitle == aSVGToken)
499*b1cdbd2cSJim Jagielski                         {
500*b1cdbd2cSJim Jagielski                             mpTarget->parseAttribute(getStrTitle(), aSVGToken, aText);
501*b1cdbd2cSJim Jagielski                         }
502*b1cdbd2cSJim Jagielski                         else // if(SVGTokenDesc == aSVGToken)
503*b1cdbd2cSJim Jagielski                         {
504*b1cdbd2cSJim Jagielski                             mpTarget->parseAttribute(getStrDesc(), aSVGToken, aText);
505*b1cdbd2cSJim Jagielski                         }
506*b1cdbd2cSJim Jagielski                     }
507*b1cdbd2cSJim Jagielski                 }
508*b1cdbd2cSJim Jagielski 
509*b1cdbd2cSJim Jagielski                 if(pCssStyle && pCssStyle->isTextCss())
510*b1cdbd2cSJim Jagielski                 {
511*b1cdbd2cSJim Jagielski                     // css style parsing
512*b1cdbd2cSJim Jagielski                     if(maCssContents.size())
513*b1cdbd2cSJim Jagielski                     {
514*b1cdbd2cSJim Jagielski                         // need to interpret css styles and remember them as StyleSheets
515*b1cdbd2cSJim Jagielski                         pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1));
516*b1cdbd2cSJim Jagielski                         maCssContents.pop_back();
517*b1cdbd2cSJim Jagielski                     }
518*b1cdbd2cSJim Jagielski                     else
519*b1cdbd2cSJim Jagielski                     {
520*b1cdbd2cSJim Jagielski                         OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
521*b1cdbd2cSJim Jagielski                     }
522*b1cdbd2cSJim Jagielski                 }
523*b1cdbd2cSJim Jagielski 
524*b1cdbd2cSJim Jagielski                 if(pWhitespaceCheck)
525*b1cdbd2cSJim Jagielski                 {
526*b1cdbd2cSJim Jagielski                     // cleanup read strings
527*b1cdbd2cSJim Jagielski                     whiteSpaceHandling(pWhitespaceCheck, 0);
528*b1cdbd2cSJim Jagielski                 }
529*b1cdbd2cSJim Jagielski             }
530*b1cdbd2cSJim Jagielski         }
531*b1cdbd2cSJim Jagielski 
characters(const::rtl::OUString & aChars)532*b1cdbd2cSJim Jagielski         void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException)
533*b1cdbd2cSJim Jagielski         {
534*b1cdbd2cSJim Jagielski             const sal_uInt32 nLength(aChars.getLength());
535*b1cdbd2cSJim Jagielski 
536*b1cdbd2cSJim Jagielski             if(mpTarget && nLength)
537*b1cdbd2cSJim Jagielski             {
538*b1cdbd2cSJim Jagielski                 switch(mpTarget->getType())
539*b1cdbd2cSJim Jagielski                 {
540*b1cdbd2cSJim Jagielski                     case SVGTokenText:
541*b1cdbd2cSJim Jagielski                     case SVGTokenTspan:
542*b1cdbd2cSJim Jagielski                     case SVGTokenTextPath:
543*b1cdbd2cSJim Jagielski                     {
544*b1cdbd2cSJim Jagielski                         const SvgNodeVector& rChilds = mpTarget->getChildren();
545*b1cdbd2cSJim Jagielski                         SvgCharacterNode* pTarget = 0;
546*b1cdbd2cSJim Jagielski 
547*b1cdbd2cSJim Jagielski                         if(rChilds.size())
548*b1cdbd2cSJim Jagielski                         {
549*b1cdbd2cSJim Jagielski                             pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]);
550*b1cdbd2cSJim Jagielski                         }
551*b1cdbd2cSJim Jagielski 
552*b1cdbd2cSJim Jagielski                         if(pTarget)
553*b1cdbd2cSJim Jagielski                         {
554*b1cdbd2cSJim Jagielski                             // concatenate to current character span
555*b1cdbd2cSJim Jagielski                             pTarget->concatenate(aChars);
556*b1cdbd2cSJim Jagielski                         }
557*b1cdbd2cSJim Jagielski                         else
558*b1cdbd2cSJim Jagielski                         {
559*b1cdbd2cSJim Jagielski                             // add character span as simplified tspan (no arguments)
560*b1cdbd2cSJim Jagielski                             // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode
561*b1cdbd2cSJim Jagielski                             new SvgCharacterNode(maDocument, mpTarget, aChars);
562*b1cdbd2cSJim Jagielski                         }
563*b1cdbd2cSJim Jagielski                         break;
564*b1cdbd2cSJim Jagielski                     }
565*b1cdbd2cSJim Jagielski                     case SVGTokenStyle:
566*b1cdbd2cSJim Jagielski                     {
567*b1cdbd2cSJim Jagielski                         SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget);
568*b1cdbd2cSJim Jagielski 
569*b1cdbd2cSJim Jagielski                         if(rSvgStyleNode.isTextCss())
570*b1cdbd2cSJim Jagielski                         {
571*b1cdbd2cSJim Jagielski                             // collect characters for css style
572*b1cdbd2cSJim Jagielski                             if(maCssContents.size())
573*b1cdbd2cSJim Jagielski                             {
574*b1cdbd2cSJim Jagielski                                 const ::rtl::OUString aTrimmedChars(aChars.trim());
575*b1cdbd2cSJim Jagielski 
576*b1cdbd2cSJim Jagielski                                 if(aTrimmedChars.getLength())
577*b1cdbd2cSJim Jagielski                                 {
578*b1cdbd2cSJim Jagielski                                     std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1);
579*b1cdbd2cSJim Jagielski                                     (*aString) += aTrimmedChars;
580*b1cdbd2cSJim Jagielski                                 }
581*b1cdbd2cSJim Jagielski                             }
582*b1cdbd2cSJim Jagielski                             else
583*b1cdbd2cSJim Jagielski                             {
584*b1cdbd2cSJim Jagielski                                 OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)");
585*b1cdbd2cSJim Jagielski                             }
586*b1cdbd2cSJim Jagielski                         }
587*b1cdbd2cSJim Jagielski                         break;
588*b1cdbd2cSJim Jagielski                     }
589*b1cdbd2cSJim Jagielski                     case SVGTokenTitle:
590*b1cdbd2cSJim Jagielski                     case SVGTokenDesc:
591*b1cdbd2cSJim Jagielski                     {
592*b1cdbd2cSJim Jagielski                         SvgTitleDescNode& rSvgTitleDescNode = static_cast< SvgTitleDescNode& >(*mpTarget);
593*b1cdbd2cSJim Jagielski 
594*b1cdbd2cSJim Jagielski                         // add text directly to SvgTitleDescNode
595*b1cdbd2cSJim Jagielski                         rSvgTitleDescNode.concatenate(aChars);
596*b1cdbd2cSJim Jagielski                         break;
597*b1cdbd2cSJim Jagielski                     }
598*b1cdbd2cSJim Jagielski                     default:
599*b1cdbd2cSJim Jagielski                     {
600*b1cdbd2cSJim Jagielski                         // characters not used by a known node
601*b1cdbd2cSJim Jagielski                         break;
602*b1cdbd2cSJim Jagielski                     }
603*b1cdbd2cSJim Jagielski                 }
604*b1cdbd2cSJim Jagielski             }
605*b1cdbd2cSJim Jagielski         }
606*b1cdbd2cSJim Jagielski 
ignorableWhitespace(const::rtl::OUString &)607*b1cdbd2cSJim Jagielski         void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException)
608*b1cdbd2cSJim Jagielski         {
609*b1cdbd2cSJim Jagielski         }
610*b1cdbd2cSJim Jagielski 
processingInstruction(const::rtl::OUString &,const::rtl::OUString &)611*b1cdbd2cSJim Jagielski         void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException)
612*b1cdbd2cSJim Jagielski         {
613*b1cdbd2cSJim Jagielski         }
614*b1cdbd2cSJim Jagielski 
setDocumentLocator(const uno::Reference<xml::sax::XLocator> &)615*b1cdbd2cSJim Jagielski         void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException)
616*b1cdbd2cSJim Jagielski         {
617*b1cdbd2cSJim Jagielski         }
618*b1cdbd2cSJim Jagielski     } // end of namespace svgreader
619*b1cdbd2cSJim Jagielski } // end of namespace svgio
620*b1cdbd2cSJim Jagielski 
621*b1cdbd2cSJim Jagielski //////////////////////////////////////////////////////////////////////////////
622*b1cdbd2cSJim Jagielski // eof
623