xref: /aoo41x/main/svgio/source/svgreader/svgnode.cxx (revision 50b37974)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svgio.hxx"
24 
25 #include <svgio/svgreader/svgnode.hxx>
26 #include <basegfx/polygon/b2dpolypolygontools.hxx>
27 #include <svgio/svgreader/svgdocument.hxx>
28 #include <svgio/svgreader/svgnode.hxx>
29 #include <svgio/svgreader/svgstyleattributes.hxx>
30 #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
31 #include <tools/urlobj.hxx>
32 
33 //////////////////////////////////////////////////////////////////////////////
34 
35 namespace svgio
36 {
37     namespace svgreader
38     {
39         const SvgStyleAttributes* SvgNode::getSvgStyleAttributes() const
40         {
41             return 0;
42         }
43 
44         const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const
45         {
46             const SvgDocument& rDocument = getDocument();
47 
48             if(rDocument.hasSvgStyleAttributesById())
49             {
50                 if(getClass())
51                 {
52                     // find all referenced CSS styles, a list of entries is allowed
53                     const rtl::OUString* pClassList = getClass();
54                     const sal_Int32 nLen(pClassList->getLength());
55                     sal_Int32 nPos(0);
56                     const SvgStyleAttributes* pNew = 0;
57 
58                     skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
59 
60                     while(nPos < nLen)
61                     {
62                         rtl::OUStringBuffer aTokenValue;
63 
64                         copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen);
65                         skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
66 
67                         rtl::OUString aId(rtl::OUString::createFromAscii("."));
68                         const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
69 
70                         // look for CSS style common to token
71                         aId = aId + aOUTokenValue;
72                         pNew = rDocument.findSvgStyleAttributesById(aId);
73 
74                         if(!pNew && rClassStr.getLength())
75                         {
76                             // look for CSS style common to class.token
77                             aId = rClassStr + aId;
78 
79                             pNew = rDocument.findSvgStyleAttributesById(aId);
80                         }
81 
82                         if(pNew)
83                         {
84                             const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
85                         }
86                     }
87                 }
88 
89                 if(maCssStyleVector.empty() && getId())
90                 {
91                     // if none found, search for CSS style equal to Id
92                     const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId());
93 
94                     if(pNew)
95                     {
96                         const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
97                     }
98                 }
99 
100                 if(maCssStyleVector.empty() && rClassStr.getLength())
101                 {
102                     // if none found, search for CSS style equal to class type
103                     const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr);
104 
105                     if(pNew)
106                     {
107                         const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
108                     }
109                 }
110             }
111 
112             if(maCssStyleVector.empty())
113             {
114                 return &rOriginal;
115             }
116             else
117             {
118                 // set CssStyleParent at maCssStyleVector members to hang them in front of
119                 // the existing style
120                 SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal);
121 
122                 for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++)
123                 {
124                     SvgStyleAttributes* pCandidate = const_cast< SvgStyleAttributes* >(maCssStyleVector[maCssStyleVector.size() - a - 1]);
125 
126                     pCandidate->setCssStyleParent(pCurrent);
127                     pCurrent = pCandidate;
128                 }
129 
130                 return pCurrent;
131             }
132         }
133 
134         SvgNode::SvgNode(
135             SVGToken aType,
136             SvgDocument& rDocument,
137             SvgNode* pParent)
138         :   maType(aType),
139             mrDocument(rDocument),
140             mpParent(pParent),
141             mpAlternativeParent(0),
142             maChildren(),
143             mpId(0),
144             mpClass(0),
145             maXmlSpace(XmlSpace_notset),
146             maCssStyleVector()
147         {
148             OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)");
149 
150             if(pParent)
151             {
152                 pParent->maChildren.push_back(this);
153             }
154             else
155             {
156 #ifdef DBG_UTIL
157                 if(SVGTokenSvg != getType())
158                 {
159                     OSL_ENSURE(false, "No parent for this node (!)");
160                 }
161 #endif
162             }
163         }
164 
165         SvgNode::~SvgNode()
166         {
167             while(maChildren.size())
168             {
169                 delete maChildren[maChildren.size() - 1];
170                 maChildren.pop_back();
171             }
172 
173             if(mpId) delete mpId;
174             if(mpClass) delete mpClass;
175         }
176 
177         void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs)
178         {
179             const sal_uInt32 nAttributes(xAttribs->getLength());
180 
181             for(sal_uInt32 a(0); a < nAttributes; a++)
182             {
183                 const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a));
184 
185                 parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a));
186             }
187         }
188 
189         void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
190         {
191             switch(aSVGToken)
192             {
193                 case SVGTokenId:
194                 {
195                     if(aContent.getLength())
196                     {
197                         setId(&aContent);
198                     }
199                     break;
200                 }
201                 case SVGTokenClass:
202                 {
203                     if(aContent.getLength())
204                     {
205                         setClass(&aContent);
206                     }
207                     break;
208                 }
209                 case SVGTokenXmlSpace:
210                 {
211                     if(aContent.getLength())
212                     {
213                         static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default"));
214                         static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve"));
215 
216                         if(aContent.match(aStrDefault))
217                         {
218                             setXmlSpace(XmlSpace_default);
219                         }
220                         else if(aContent.match(aStrPreserve))
221                         {
222                             setXmlSpace(XmlSpace_preserve);
223                         }
224                     }
225                     break;
226                 }
227                 default:
228                 {
229                     break;
230                 }
231             }
232         }
233 
234         void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
235         {
236             if(!bReferenced)
237             {
238                 if(SVGTokenDefs == getType() ||
239                     SVGTokenSymbol == getType() ||
240                     SVGTokenClipPathNode == getType() ||
241                     SVGTokenMask == getType() ||
242                     SVGTokenMarker == getType() ||
243                     SVGTokenPattern == getType())
244                 {
245                     // do not decompose defs or symbol nodes (these hold only style-like
246                     // objects which may be used by referencing them) except when doing
247                     // so controlled referenced
248 
249                     // also do not decompose ClipPaths and Masks. These should be embedded
250                     // in a defs node (which gets not decomposed by itself), but you never
251                     // know
252 
253                     // also not directly used are Markers and Patterns, only indirecty used
254                     // by reference
255                     return;
256                 }
257             }
258 
259             const SvgNodeVector& rChildren = getChildren();
260 
261             if(!rChildren.empty())
262             {
263                 const sal_uInt32 nCount(rChildren.size());
264 
265                 for(sal_uInt32 a(0); a < nCount; a++)
266                 {
267                     SvgNode* pCandidate = rChildren[a];
268 
269                     if(pCandidate)
270                     {
271                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
272 
273                         pCandidate->decomposeSvgNode(aNewTarget, bReferenced);
274 
275                         if(aNewTarget.hasElements())
276                         {
277                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
278                         }
279                     }
280                     else
281                     {
282                         OSL_ENSURE(false, "Null-Pointer in child node list (!)");
283                     }
284                 }
285 
286                 if(rTarget.hasElements())
287                 {
288                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
289 
290                     if(pStyles)
291                     {
292                         // check if we have Title or Desc
293                         const rtl::OUString& rTitle = pStyles->getTitle();
294                         const rtl::OUString& rDesc = pStyles->getDesc();
295 
296                         if(rTitle.getLength() || rDesc.getLength())
297                         {
298                             // default object name is empty
299                             rtl::OUString aObjectName;
300 
301                             // use path as object name when outmost element
302                             if(SVGTokenSvg == getType())
303                             {
304                                 aObjectName = getDocument().getAbsolutePath();
305 
306                                 if(aObjectName.getLength())
307                                 {
308                             		INetURLObject aURL(aObjectName);
309 
310                                     aObjectName = aURL.getName(
311                                         INetURLObject::LAST_SEGMENT,
312                                         true,
313                                         INetURLObject::DECODE_WITH_CHARSET);
314                                 }
315                             }
316 
317                             // pack in ObjectInfoPrimitive2D group
318                             const drawinglayer::primitive2d::Primitive2DReference xRef(
319                                 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
320                                     rTarget,
321                                     aObjectName,
322                                     rTitle,
323                                     rDesc));
324 
325                             rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
326                         }
327                     }
328                 }
329             }
330         }
331 
332         const basegfx::B2DRange* SvgNode::getCurrentViewPort() const
333         {
334             if(getParent())
335             {
336                 return getParent()->getCurrentViewPort();
337             }
338             else
339             {
340                 return 0;
341             }
342         }
343 
344         double SvgNode::getCurrentFontSize() const
345         {
346             if(getSvgStyleAttributes())
347             {
348                 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate);
349             }
350             else if(getParent())
351             {
352                 return getParent()->getCurrentFontSize();
353             }
354             else
355             {
356                 return 0.0;
357             }
358         }
359 
360         double SvgNode::getCurrentXHeight() const
361         {
362             if(getSvgStyleAttributes())
363             {
364                 // for XHeight, use FontSize currently
365                 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate);
366             }
367             else if(getParent())
368             {
369                 return getParent()->getCurrentXHeight();
370             }
371             else
372             {
373                 return 0.0;
374             }
375         }
376 
377         void SvgNode::setId(const rtl::OUString* pfId)
378         {
379             if(mpId)
380             {
381                 mrDocument.removeSvgNodeFromMapper(*mpId);
382                 delete mpId;
383                 mpId = 0;
384             }
385 
386             if(pfId)
387             {
388                 mpId = new rtl::OUString(*pfId);
389                 mrDocument.addSvgNodeToMapper(*mpId, *this);
390             }
391         }
392 
393         void SvgNode::setClass(const rtl::OUString* pfClass)
394         {
395             if(mpClass)
396             {
397                 mrDocument.removeSvgNodeFromMapper(*mpClass);
398                 delete mpClass;
399                 mpClass = 0;
400             }
401 
402             if(pfClass)
403             {
404                 mpClass = new rtl::OUString(*pfClass);
405                 mrDocument.addSvgNodeToMapper(*mpClass, *this);
406             }
407         }
408 
409         XmlSpace SvgNode::getXmlSpace() const
410         {
411             if(maXmlSpace != XmlSpace_notset)
412             {
413                 return maXmlSpace;
414             }
415 
416             if(getParent())
417             {
418                 return getParent()->getXmlSpace();
419             }
420 
421             // default is XmlSpace_default
422             return XmlSpace_default;
423         }
424 
425     } // end of namespace svgreader
426 } // end of namespace svgio
427 
428 //////////////////////////////////////////////////////////////////////////////
429 // eof
430