xref: /aoo41x/main/svgio/source/svgreader/svgnode.cxx (revision 01e92ad6)
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         Display getDisplayFromContent(const rtl::OUString& aContent)
198         {
199             if(aContent.getLength())
200             {
201                 static rtl::OUString aStrInline(rtl::OUString::createFromAscii("inline"));
202                 static rtl::OUString aStrBlock(rtl::OUString::createFromAscii("block"));
203                 static rtl::OUString aStrList_item(rtl::OUString::createFromAscii("list-item"));
204                 static rtl::OUString aStrRun_in(rtl::OUString::createFromAscii("run-in"));
205                 static rtl::OUString aStrCompact(rtl::OUString::createFromAscii("compact"));
206                 static rtl::OUString aStrMarker(rtl::OUString::createFromAscii("marker"));
207                 static rtl::OUString aStrTable(rtl::OUString::createFromAscii("table"));
208                 static rtl::OUString aStrInline_table(rtl::OUString::createFromAscii("inline-table"));
209                 static rtl::OUString aStrTable_row_group(rtl::OUString::createFromAscii("table-row-group"));
210                 static rtl::OUString aStrTable_header_group(rtl::OUString::createFromAscii("table-header-group"));
211                 static rtl::OUString aStrTable_footer_group(rtl::OUString::createFromAscii("table-footer-group"));
212                 static rtl::OUString aStrTable_row(rtl::OUString::createFromAscii("table-row"));
213                 static rtl::OUString aStrTable_column_group(rtl::OUString::createFromAscii("table-column-group"));
214                 static rtl::OUString aStrTable_column(rtl::OUString::createFromAscii("table-column"));
215                 static rtl::OUString aStrTable_cell(rtl::OUString::createFromAscii("table-cell"));
216                 static rtl::OUString aStrTable_caption(rtl::OUString::createFromAscii("table-caption"));
217                 static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
218                 static rtl::OUString aStrInherit(rtl::OUString::createFromAscii("inherit"));
219 
220                 if(aContent.match(aStrInline))
221                 {
222                     return Display_inline;
223                 }
224                 else if(aContent.match(aStrNone))
225                 {
226                     return Display_none;
227                 }
228                 else if(aContent.match(aStrInherit))
229                 {
230                     return Display_inherit;
231                 }
232                 else if(aContent.match(aStrBlock))
233                 {
234                     return Display_block;
235                 }
236                 else if(aContent.match(aStrList_item))
237                 {
238                     return Display_list_item;
239                 }
240                 else if(aContent.match(aStrRun_in))
241                 {
242                     return Display_run_in;
243                 }
244                 else if(aContent.match(aStrCompact))
245                 {
246                     return Display_compact;
247                 }
248                 else if(aContent.match(aStrMarker))
249                 {
250                     return Display_marker;
251                 }
252                 else if(aContent.match(aStrTable))
253                 {
254                     return Display_table;
255                 }
256                 else if(aContent.match(aStrInline_table))
257                 {
258                     return Display_inline_table;
259                 }
260                 else if(aContent.match(aStrTable_row_group))
261                 {
262                     return Display_table_row_group;
263                 }
264                 else if(aContent.match(aStrTable_header_group))
265                 {
266                     return Display_table_header_group;
267                 }
268                 else if(aContent.match(aStrTable_footer_group))
269                 {
270                     return Display_table_footer_group;
271                 }
272                 else if(aContent.match(aStrTable_row))
273                 {
274                     return Display_table_row;
275                 }
276                 else if(aContent.match(aStrTable_column_group))
277                 {
278                     return Display_table_column_group;
279                 }
280                 else if(aContent.match(aStrTable_column))
281                 {
282                     return Display_table_column;
283                 }
284                 else if(aContent.match(aStrTable_cell))
285                 {
286                     return Display_table_cell;
287                 }
288                 else if(aContent.match(aStrTable_caption))
289                 {
290                     return Display_table_caption;
291                 }
292             }
293 
294             // return the default
295             return Display_inline;
296         }
297 
298         void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
299         {
300             switch(aSVGToken)
301             {
302                 case SVGTokenId:
303                 {
304                     if(aContent.getLength())
305                     {
306                         setId(&aContent);
307                     }
308                     break;
309                 }
310                 case SVGTokenClass:
311                 {
312                     if(aContent.getLength())
313                     {
314                         setClass(&aContent);
315                     }
316                     break;
317                 }
318                 case SVGTokenXmlSpace:
319                 {
320                     if(aContent.getLength())
321                     {
322                         static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default"));
323                         static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve"));
324 
325                         if(aContent.match(aStrDefault))
326                         {
327                             setXmlSpace(XmlSpace_default);
328                         }
329                         else if(aContent.match(aStrPreserve))
330                         {
331                             setXmlSpace(XmlSpace_preserve);
332                         }
333                     }
334                     break;
335                 }
336                 case SVGTokenDisplay:
337                 {
338                     if(aContent.getLength())
339                     {
340                         setDisplay(getDisplayFromContent(aContent));
341                     }
342                     break;
343                 }
344                 default:
345                 {
346                     break;
347                 }
348             }
349         }
350 
351         void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
352         {
353             if(Display_none == getDisplay())
354             {
355                 return;
356             }
357 
358             if(!bReferenced)
359             {
360                 if(SVGTokenDefs == getType() ||
361                     SVGTokenSymbol == getType() ||
362                     SVGTokenClipPathNode == getType() ||
363                     SVGTokenMask == getType() ||
364                     SVGTokenMarker == getType() ||
365                     SVGTokenPattern == getType())
366                 {
367                     // do not decompose defs or symbol nodes (these hold only style-like
368                     // objects which may be used by referencing them) except when doing
369                     // so controlled referenced
370 
371                     // also do not decompose ClipPaths and Masks. These should be embedded
372                     // in a defs node (which gets not decomposed by itself), but you never
373                     // know
374 
375                     // also not directly used are Markers and Patterns, only indirecty used
376                     // by reference
377 
378                     // #121656# also do not decompose nodes which have display="none" set
379                     // as property
380                     return;
381                 }
382             }
383 
384             const SvgNodeVector& rChildren = getChildren();
385 
386             if(!rChildren.empty())
387             {
388                 const sal_uInt32 nCount(rChildren.size());
389 
390                 for(sal_uInt32 a(0); a < nCount; a++)
391                 {
392                     SvgNode* pCandidate = rChildren[a];
393 
394                     if(pCandidate && Display_none != pCandidate->getDisplay())
395                     {
396                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
397 
398                         pCandidate->decomposeSvgNode(aNewTarget, bReferenced);
399 
400                         if(aNewTarget.hasElements())
401                         {
402                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
403                         }
404                     }
405                     else
406                     {
407                         OSL_ENSURE(false, "Null-Pointer in child node list (!)");
408                     }
409                 }
410 
411                 if(rTarget.hasElements())
412                 {
413                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
414 
415                     if(pStyles)
416                     {
417                         // check if we have Title or Desc
418                         const rtl::OUString& rTitle = pStyles->getTitle();
419                         const rtl::OUString& rDesc = pStyles->getDesc();
420 
421                         if(rTitle.getLength() || rDesc.getLength())
422                         {
423                             // default object name is empty
424                             rtl::OUString aObjectName;
425 
426                             // use path as object name when outmost element
427                             if(SVGTokenSvg == getType())
428                             {
429                                 aObjectName = getDocument().getAbsolutePath();
430 
431                                 if(aObjectName.getLength())
432                                 {
433                             		INetURLObject aURL(aObjectName);
434 
435                                     aObjectName = aURL.getName(
436                                         INetURLObject::LAST_SEGMENT,
437                                         true,
438                                         INetURLObject::DECODE_WITH_CHARSET);
439                                 }
440                             }
441 
442                             // pack in ObjectInfoPrimitive2D group
443                             const drawinglayer::primitive2d::Primitive2DReference xRef(
444                                 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
445                                     rTarget,
446                                     aObjectName,
447                                     rTitle,
448                                     rDesc));
449 
450                             rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
451                         }
452                     }
453                 }
454             }
455         }
456 
457         const basegfx::B2DRange* SvgNode::getCurrentViewPort() const
458         {
459             if(getParent())
460             {
461                 return getParent()->getCurrentViewPort();
462             }
463             else
464             {
465                 return 0;
466             }
467         }
468 
469         double SvgNode::getCurrentFontSize() const
470         {
471             if(getSvgStyleAttributes())
472             {
473                 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate);
474             }
475             else if(getParent())
476             {
477                 return getParent()->getCurrentFontSize();
478             }
479             else
480             {
481                 return 0.0;
482             }
483         }
484 
485         double SvgNode::getCurrentXHeight() const
486         {
487             if(getSvgStyleAttributes())
488             {
489                 // for XHeight, use FontSize currently
490                 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate);
491             }
492             else if(getParent())
493             {
494                 return getParent()->getCurrentXHeight();
495             }
496             else
497             {
498                 return 0.0;
499             }
500         }
501 
502         void SvgNode::setId(const rtl::OUString* pfId)
503         {
504             if(mpId)
505             {
506                 mrDocument.removeSvgNodeFromMapper(*mpId);
507                 delete mpId;
508                 mpId = 0;
509             }
510 
511             if(pfId)
512             {
513                 mpId = new rtl::OUString(*pfId);
514                 mrDocument.addSvgNodeToMapper(*mpId, *this);
515             }
516         }
517 
518         void SvgNode::setClass(const rtl::OUString* pfClass)
519         {
520             if(mpClass)
521             {
522                 mrDocument.removeSvgNodeFromMapper(*mpClass);
523                 delete mpClass;
524                 mpClass = 0;
525             }
526 
527             if(pfClass)
528             {
529                 mpClass = new rtl::OUString(*pfClass);
530                 mrDocument.addSvgNodeToMapper(*mpClass, *this);
531             }
532         }
533 
534         XmlSpace SvgNode::getXmlSpace() const
535         {
536             if(maXmlSpace != XmlSpace_notset)
537             {
538                 return maXmlSpace;
539             }
540 
541             if(getParent())
542             {
543                 return getParent()->getXmlSpace();
544             }
545 
546             // default is XmlSpace_default
547             return XmlSpace_default;
548         }
549 
550     } // end of namespace svgreader
551 } // end of namespace svgio
552 
553 //////////////////////////////////////////////////////////////////////////////
554 // eof
555