xref: /aoo42x/main/svgio/source/svgreader/svgnode.cxx (revision a275c134)
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             if(maCssStyleVector.empty()) // #120435# Evaluate for CSS styles only once, this cannot change
47             {
48                 const SvgDocument& rDocument = getDocument();
49 
50                 if(rDocument.hasSvgStyleAttributesById())
51                 {
52                     if(getClass())
53                     {
54                         // find all referenced CSS styles, a list of entries is allowed
55                         const rtl::OUString* pClassList = getClass();
56                         const sal_Int32 nLen(pClassList->getLength());
57                         sal_Int32 nPos(0);
58                         const SvgStyleAttributes* pNew = 0;
59 
60                         skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
61 
62                         while(nPos < nLen)
63                         {
64                             rtl::OUStringBuffer aTokenValue;
65 
66                             copyToLimiter(*pClassList, sal_Unicode(' '), nPos, aTokenValue, nLen);
67                             skip_char(*pClassList, sal_Unicode(' '), nPos, nLen);
68 
69                             rtl::OUString aId(rtl::OUString::createFromAscii("."));
70                             const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
71 
72                             // look for CSS style common to token
73                             aId = aId + aOUTokenValue;
74                             pNew = rDocument.findSvgStyleAttributesById(aId);
75 
76                             if(!pNew && rClassStr.getLength())
77                             {
78                                 // look for CSS style common to class.token
79                                 aId = rClassStr + aId;
80 
81                                 pNew = rDocument.findSvgStyleAttributesById(aId);
82                             }
83 
84                             if(pNew)
85                             {
86                                 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
87                             }
88                         }
89                     }
90 
91                     if(maCssStyleVector.empty() && getId())
92                     {
93                         // if none found, search for CSS style equal to Id
94                         const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId());
95 
96                         if(pNew)
97                         {
98                             const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
99                         }
100                     }
101 
102                     if(maCssStyleVector.empty() && rClassStr.getLength())
103                     {
104                         // if none found, search for CSS style equal to class type
105                         const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr);
106 
107                         if(pNew)
108                         {
109                             const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
110                         }
111                     }
112                 }
113             }
114 
115             if(maCssStyleVector.empty())
116             {
117                 return &rOriginal;
118             }
119             else
120             {
121                 // set CssStyleParent at maCssStyleVector members to hang them in front of
122                 // the existing style. Build a style chain, reset parent of original for security.
123                 // Repeated style requests should only be issued from sub-Text nodes and I'm not
124                 // sure if in-between text nodes may build other chains (should not happen). But
125                 // it's only a re-chaining with pointers (cheap), so allow to do it every time.
126                 SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal);
127                 pCurrent->setCssStyleParent(0);
128 
129                 for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++)
130                 {
131                     SvgStyleAttributes* pCandidate = const_cast< SvgStyleAttributes* >(maCssStyleVector[maCssStyleVector.size() - a - 1]);
132 
133                     pCandidate->setCssStyleParent(pCurrent);
134                     pCurrent = pCandidate;
135                 }
136 
137                 return pCurrent;
138             }
139         }
140 
141         SvgNode::SvgNode(
142             SVGToken aType,
143             SvgDocument& rDocument,
144             SvgNode* pParent)
145         :   maType(aType),
146             mrDocument(rDocument),
147             mpParent(pParent),
148             mpAlternativeParent(0),
149             maChildren(),
150             mpId(0),
151             mpClass(0),
152             maXmlSpace(XmlSpace_notset),
153             maDisplay(Display_inline),
154             maCssStyleVector()
155         {
156             OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)");
157 
158             if(pParent)
159             {
160                 pParent->maChildren.push_back(this);
161             }
162             else
163             {
164 #ifdef DBG_UTIL
165                 if(SVGTokenSvg != getType())
166                 {
167                     OSL_ENSURE(false, "No parent for this node (!)");
168                 }
169 #endif
170             }
171         }
172 
173         SvgNode::~SvgNode()
174         {
175             while(maChildren.size())
176             {
177                 delete maChildren[maChildren.size() - 1];
178                 maChildren.pop_back();
179             }
180 
181             if(mpId) delete mpId;
182             if(mpClass) delete mpClass;
183         }
184 
185         void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs)
186         {
187             const sal_uInt32 nAttributes(xAttribs->getLength());
188 
189             for(sal_uInt32 a(0); a < nAttributes; a++)
190             {
191                 const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a));
192 
193                 parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a));
194             }
195         }
196 
197         void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
198         {
199             switch(aSVGToken)
200             {
201                 case SVGTokenId:
202                 {
203                     if(aContent.getLength())
204                     {
205                         setId(&aContent);
206                     }
207                     break;
208                 }
209                 case SVGTokenClass:
210                 {
211                     if(aContent.getLength())
212                     {
213                         setClass(&aContent);
214                     }
215                     break;
216                 }
217                 case SVGTokenXmlSpace:
218                 {
219                     if(aContent.getLength())
220                     {
221                         static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default"));
222                         static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve"));
223 
224                         if(aContent.match(aStrDefault))
225                         {
226                             setXmlSpace(XmlSpace_default);
227                         }
228                         else if(aContent.match(aStrPreserve))
229                         {
230                             setXmlSpace(XmlSpace_preserve);
231                         }
232                     }
233                     break;
234                 }
235                 case SVGTokenDisplay:
236                 {
237                     if(aContent.getLength())
238                     {
239                         static rtl::OUString aStrInline(rtl::OUString::createFromAscii("inline"));
240                         static rtl::OUString aStrBlock(rtl::OUString::createFromAscii("block"));
241                         static rtl::OUString aStrList_item(rtl::OUString::createFromAscii("list-item"));
242                         static rtl::OUString aStrRun_in(rtl::OUString::createFromAscii("run-in"));
243                         static rtl::OUString aStrCompact(rtl::OUString::createFromAscii("compact"));
244                         static rtl::OUString aStrMarker(rtl::OUString::createFromAscii("marker"));
245                         static rtl::OUString aStrTable(rtl::OUString::createFromAscii("table"));
246                         static rtl::OUString aStrInline_table(rtl::OUString::createFromAscii("inline-table"));
247                         static rtl::OUString aStrTable_row_group(rtl::OUString::createFromAscii("table-row-group"));
248                         static rtl::OUString aStrTable_header_group(rtl::OUString::createFromAscii("table-header-group"));
249                         static rtl::OUString aStrTable_footer_group(rtl::OUString::createFromAscii("table-footer-group"));
250                         static rtl::OUString aStrTable_row(rtl::OUString::createFromAscii("table-row"));
251                         static rtl::OUString aStrTable_column_group(rtl::OUString::createFromAscii("table-column-group"));
252                         static rtl::OUString aStrTable_column(rtl::OUString::createFromAscii("table-column"));
253                         static rtl::OUString aStrTable_cell(rtl::OUString::createFromAscii("table-cell"));
254                         static rtl::OUString aStrTable_caption(rtl::OUString::createFromAscii("table-caption"));
255                         static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
256                         static rtl::OUString aStrInherit(rtl::OUString::createFromAscii("inherit"));
257 
258                         if(aContent.match(aStrInline))
259                         {
260                             setDisplay(Display_inline);
261                         }
262                         else if(aContent.match(aStrNone))
263                         {
264                             setDisplay(Display_none);
265                         }
266                         else if(aContent.match(aStrInherit))
267                         {
268                             setDisplay(Display_inherit);
269                         }
270                         else if(aContent.match(aStrBlock))
271                         {
272                             setDisplay(Display_block);
273                         }
274                         else if(aContent.match(aStrList_item))
275                         {
276                             setDisplay(Display_list_item);
277                         }
278                         else if(aContent.match(aStrRun_in))
279                         {
280                             setDisplay(Display_run_in);
281                         }
282                         else if(aContent.match(aStrCompact))
283                         {
284                             setDisplay(Display_compact);
285                         }
286                         else if(aContent.match(aStrMarker))
287                         {
288                             setDisplay(Display_marker);
289                         }
290                         else if(aContent.match(aStrTable))
291                         {
292                             setDisplay(Display_table);
293                         }
294                         else if(aContent.match(aStrInline_table))
295                         {
296                             setDisplay(Display_inline_table);
297                         }
298                         else if(aContent.match(aStrTable_row_group))
299                         {
300                             setDisplay(Display_table_row_group);
301                         }
302                         else if(aContent.match(aStrTable_header_group))
303                         {
304                             setDisplay(Display_table_header_group);
305                         }
306                         else if(aContent.match(aStrTable_footer_group))
307                         {
308                             setDisplay(Display_table_footer_group);
309                         }
310                         else if(aContent.match(aStrTable_row))
311                         {
312                             setDisplay(Display_table_row);
313                         }
314                         else if(aContent.match(aStrTable_column_group))
315                         {
316                             setDisplay(Display_table_column_group);
317                         }
318                         else if(aContent.match(aStrTable_column))
319                         {
320                             setDisplay(Display_table_column);
321                         }
322                         else if(aContent.match(aStrTable_cell))
323                         {
324                             setDisplay(Display_table_cell);
325                         }
326                         else if(aContent.match(aStrTable_caption))
327                         {
328                             setDisplay(Display_table_caption);
329                         }
330                     }
331                     break;
332                 }
333                 default:
334                 {
335                     break;
336                 }
337             }
338         }
339 
340         void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
341         {
342             if(Display_none == getDisplay())
343             {
344                 return;
345             }
346 
347             if(!bReferenced)
348             {
349                 if(SVGTokenDefs == getType() ||
350                     SVGTokenSymbol == getType() ||
351                     SVGTokenClipPathNode == getType() ||
352                     SVGTokenMask == getType() ||
353                     SVGTokenMarker == getType() ||
354                     SVGTokenPattern == getType())
355                 {
356                     // do not decompose defs or symbol nodes (these hold only style-like
357                     // objects which may be used by referencing them) except when doing
358                     // so controlled referenced
359 
360                     // also do not decompose ClipPaths and Masks. These should be embedded
361                     // in a defs node (which gets not decomposed by itself), but you never
362                     // know
363 
364                     // also not directly used are Markers and Patterns, only indirecty used
365                     // by reference
366 
367                     // #121656# also do not decompose nodes which have display="none" set
368                     // as property
369                     return;
370                 }
371             }
372 
373             const SvgNodeVector& rChildren = getChildren();
374 
375             if(!rChildren.empty())
376             {
377                 const sal_uInt32 nCount(rChildren.size());
378 
379                 for(sal_uInt32 a(0); a < nCount; a++)
380                 {
381                     SvgNode* pCandidate = rChildren[a];
382 
383                     if(pCandidate && Display_none != pCandidate->getDisplay())
384                     {
385                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
386 
387                         pCandidate->decomposeSvgNode(aNewTarget, bReferenced);
388 
389                         if(aNewTarget.hasElements())
390                         {
391                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
392                         }
393                     }
394                     else
395                     {
396                         OSL_ENSURE(false, "Null-Pointer in child node list (!)");
397                     }
398                 }
399 
400                 if(rTarget.hasElements())
401                 {
402                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
403 
404                     if(pStyles)
405                     {
406                         // check if we have Title or Desc
407                         const rtl::OUString& rTitle = pStyles->getTitle();
408                         const rtl::OUString& rDesc = pStyles->getDesc();
409 
410                         if(rTitle.getLength() || rDesc.getLength())
411                         {
412                             // default object name is empty
413                             rtl::OUString aObjectName;
414 
415                             // use path as object name when outmost element
416                             if(SVGTokenSvg == getType())
417                             {
418                                 aObjectName = getDocument().getAbsolutePath();
419 
420                                 if(aObjectName.getLength())
421                                 {
422                             		INetURLObject aURL(aObjectName);
423 
424                                     aObjectName = aURL.getName(
425                                         INetURLObject::LAST_SEGMENT,
426                                         true,
427                                         INetURLObject::DECODE_WITH_CHARSET);
428                                 }
429                             }
430 
431                             // pack in ObjectInfoPrimitive2D group
432                             const drawinglayer::primitive2d::Primitive2DReference xRef(
433                                 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
434                                     rTarget,
435                                     aObjectName,
436                                     rTitle,
437                                     rDesc));
438 
439                             rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
440                         }
441                     }
442                 }
443             }
444         }
445 
446         const basegfx::B2DRange* SvgNode::getCurrentViewPort() const
447         {
448             if(getParent())
449             {
450                 return getParent()->getCurrentViewPort();
451             }
452             else
453             {
454                 return 0;
455             }
456         }
457 
458         double SvgNode::getCurrentFontSize() const
459         {
460             if(getSvgStyleAttributes())
461             {
462                 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate);
463             }
464             else if(getParent())
465             {
466                 return getParent()->getCurrentFontSize();
467             }
468             else
469             {
470                 return 0.0;
471             }
472         }
473 
474         double SvgNode::getCurrentXHeight() const
475         {
476             if(getSvgStyleAttributes())
477             {
478                 // for XHeight, use FontSize currently
479                 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate);
480             }
481             else if(getParent())
482             {
483                 return getParent()->getCurrentXHeight();
484             }
485             else
486             {
487                 return 0.0;
488             }
489         }
490 
491         void SvgNode::setId(const rtl::OUString* pfId)
492         {
493             if(mpId)
494             {
495                 mrDocument.removeSvgNodeFromMapper(*mpId);
496                 delete mpId;
497                 mpId = 0;
498             }
499 
500             if(pfId)
501             {
502                 mpId = new rtl::OUString(*pfId);
503                 mrDocument.addSvgNodeToMapper(*mpId, *this);
504             }
505         }
506 
507         void SvgNode::setClass(const rtl::OUString* pfClass)
508         {
509             if(mpClass)
510             {
511                 mrDocument.removeSvgNodeFromMapper(*mpClass);
512                 delete mpClass;
513                 mpClass = 0;
514             }
515 
516             if(pfClass)
517             {
518                 mpClass = new rtl::OUString(*pfClass);
519                 mrDocument.addSvgNodeToMapper(*mpClass, *this);
520             }
521         }
522 
523         XmlSpace SvgNode::getXmlSpace() const
524         {
525             if(maXmlSpace != XmlSpace_notset)
526             {
527                 return maXmlSpace;
528             }
529 
530             if(getParent())
531             {
532                 return getParent()->getXmlSpace();
533             }
534 
535             // default is XmlSpace_default
536             return XmlSpace_default;
537         }
538 
539     } // end of namespace svgreader
540 } // end of namespace svgio
541 
542 //////////////////////////////////////////////////////////////////////////////
543 // eof
544