LCOV - code coverage report
Current view: top level - svgio/source/svgreader - svgnode.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 79 210 37.6 %
Date: 2014-04-11 Functions: 7 17 41.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      21             : #include <svgio/svgreader/svgdocument.hxx>
      22             : #include <svgio/svgreader/svgnode.hxx>
      23             : #include <svgio/svgreader/svgstyleattributes.hxx>
      24             : #include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
      25             : #include <tools/urlobj.hxx>
      26             : 
      27             : 
      28             : namespace svgio
      29             : {
      30             :     namespace svgreader
      31             :     {
      32           0 :         const SvgStyleAttributes* SvgNode::getSvgStyleAttributes() const
      33             :         {
      34           0 :             return 0;
      35             :         }
      36             : 
      37      103326 :         const SvgStyleAttributes* SvgNode::checkForCssStyle(const rtl::OUString& rClassStr, const SvgStyleAttributes& rOriginal) const
      38             :         {
      39      103326 :             if(maCssStyleVector.empty()) // #120435# Evaluate for CSS styles only once, this cannot change
      40             :             {
      41      103326 :                 const SvgDocument& rDocument = getDocument();
      42             : 
      43      103326 :                 if(rDocument.hasSvgStyleAttributesById())
      44             :                 {
      45           0 :                     if(getClass())
      46             :                     {
      47             :                         // find all referenced CSS styles, a list of entries is allowed
      48           0 :                         const rtl::OUString* pClassList = getClass();
      49           0 :                         const sal_Int32 nLen(pClassList->getLength());
      50           0 :                         sal_Int32 nPos(0);
      51           0 :                         const SvgStyleAttributes* pNew = 0;
      52             : 
      53           0 :                         skip_char(*pClassList, ' ', nPos, nLen);
      54             : 
      55           0 :                         while(nPos < nLen)
      56             :                         {
      57           0 :                             rtl::OUStringBuffer aTokenValue;
      58             : 
      59           0 :                             copyToLimiter(*pClassList, ' ', nPos, aTokenValue, nLen);
      60           0 :                             skip_char(*pClassList, ' ', nPos, nLen);
      61             : 
      62           0 :                             rtl::OUString aId(".");
      63           0 :                             const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
      64             : 
      65             :                             // look for CSS style common to token
      66           0 :                             aId += aOUTokenValue;
      67           0 :                             pNew = rDocument.findSvgStyleAttributesById(aId);
      68             : 
      69           0 :                             if(!pNew && !rClassStr.isEmpty())
      70             :                             {
      71             :                                 // look for CSS style common to class.token
      72           0 :                                 aId = rClassStr + aId;
      73             : 
      74           0 :                                 pNew = rDocument.findSvgStyleAttributesById(aId);
      75             :                             }
      76             : 
      77           0 :                             if(pNew)
      78             :                             {
      79           0 :                                 const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
      80             :                             }
      81           0 :                         }
      82             :                     }
      83             : 
      84           0 :                     if(maCssStyleVector.empty() && getId())
      85             :                     {
      86             :                         // if none found, search for CSS style equal to Id
      87           0 :                         const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(*getId());
      88             : 
      89           0 :                         if(pNew)
      90             :                         {
      91           0 :                             const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
      92             :                         }
      93             :                     }
      94             : 
      95           0 :                     if(maCssStyleVector.empty() && !rClassStr.isEmpty())
      96             :                     {
      97             :                         // if none found, search for CSS style equal to class type
      98           0 :                         const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(rClassStr);
      99             : 
     100           0 :                         if(pNew)
     101             :                         {
     102           0 :                             const_cast< SvgNode* >(this)->maCssStyleVector.push_back(pNew);
     103             :                         }
     104             :                     }
     105             :                 }
     106             :             }
     107             : 
     108      103326 :             if(!maCssStyleVector.empty())
     109             :             {
     110             :                 // #i123510# if CSS styles were found, create a linked list with rOriginal as parent
     111             :                 // and all CSS styles as linked children, so that the style attribute has
     112             :                 // priority over the CSS style. If there is no style attribute this means that
     113             :                 // no values are set at rOriginal, thus it is still correct to have that order.
     114             :                 // Repeated style requests should only be issued from sub-Text nodes and I'm not
     115             :                 // sure if in-between text nodes may build other chains (should not happen). But
     116             :                 // it's only a re-chaining with pointers (cheap), so allow to do it every time.
     117           0 :                 SvgStyleAttributes* pCurrent = const_cast< SvgStyleAttributes* >(&rOriginal);
     118           0 :                 pCurrent->setCssStyleParent(0);
     119             : 
     120           0 :                 for(sal_uInt32 a(0); a < maCssStyleVector.size(); a++)
     121             :                 {
     122           0 :                     SvgStyleAttributes* pNext = const_cast< SvgStyleAttributes* >(maCssStyleVector[a]);
     123             : 
     124           0 :                     pCurrent->setCssStyleParent(pNext);
     125           0 :                     pCurrent = pNext;
     126           0 :                     pCurrent->setCssStyleParent(0);
     127             :                 }
     128             :             }
     129             : 
     130      103326 :             return &rOriginal;
     131             :         }
     132             : 
     133       10759 :         SvgNode::SvgNode(
     134             :             SVGToken aType,
     135             :             SvgDocument& rDocument,
     136             :             SvgNode* pParent)
     137             :         :   maType(aType),
     138             :             mrDocument(rDocument),
     139             :             mpParent(pParent),
     140             :             mpAlternativeParent(0),
     141             :             maChildren(),
     142             :             mpId(0),
     143             :             mpClass(0),
     144             :             maXmlSpace(XmlSpace_notset),
     145             :             maDisplay(Display_inline),
     146       10759 :             maCssStyleVector()
     147             :         {
     148             :             OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)");
     149             : 
     150       10759 :             if(pParent)
     151             :             {
     152       10467 :                 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       10759 :         }
     164             : 
     165       21518 :         SvgNode::~SvgNode()
     166             :         {
     167       31985 :             while(maChildren.size())
     168             :             {
     169       10467 :                 delete maChildren[maChildren.size() - 1];
     170       10467 :                 maChildren.pop_back();
     171             :             }
     172             : 
     173       10759 :             if(mpId) delete mpId;
     174       10759 :             if(mpClass) delete mpClass;
     175       10759 :         }
     176             : 
     177       10759 :         void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs)
     178             :         {
     179       10759 :             const sal_uInt32 nAttributes(xAttribs->getLength());
     180             :             // #i122522# SVG defines that 'In general, this means that the presentation attributes have
     181             :             // lower priority than other CSS style rules specified in author style sheets or style
     182             :             // attributes.' in http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes
     183             :             // (6.4 Specifying properties using the presentation attributes SVG 1.1). That means that
     184             :             // e.g. font-size will appear as presentation attribute and CSS style attribute. In these
     185             :             // cases, CSS style attributes need to have precedence. To do so it is possible to create
     186             :             // a proirity system for all properties of a shape, but it will also work to parse the
     187             :             // presentation attributes of type 'style' last, so they will overwrite the less-prioritized
     188             :             // already interpreted ones. Thus, remember SVGTokenStyle entries and parse them last.
     189             :             // To make this work it is required that parseAttribute is only called by parseAttributes
     190             :             // which is the case.
     191       10759 :             std::vector< sal_uInt32 > aSVGTokenStyleIndexes;
     192             : 
     193       40049 :             for(sal_uInt32 a(0); a < nAttributes; a++)
     194             :             {
     195       29290 :                 const OUString aTokenName(xAttribs->getNameByIndex(a));
     196       29290 :                 const SVGToken aSVGToken(StrToSVGToken(aTokenName));
     197             : 
     198       29290 :                 if(SVGTokenStyle == aSVGToken)
     199             :                 {
     200             :                     // #i122522# remember SVGTokenStyle entry
     201        3566 :                     aSVGTokenStyleIndexes.push_back(a);
     202             :                 }
     203             :                 else
     204             :                 {
     205       25724 :                     parseAttribute(aTokenName, aSVGToken, xAttribs->getValueByIndex(a));
     206             :                 }
     207       29290 :             }
     208             : 
     209             :             // #i122522# parse SVGTokenStyle entries last to override already interpreted
     210             :             // 'presentation attributes' of potenially the same type
     211       14325 :             for(sal_uInt32 b(0); b < aSVGTokenStyleIndexes.size(); b++)
     212             :             {
     213        3566 :                 const sal_uInt32 nSVGTokenStyleIndex(aSVGTokenStyleIndexes[b]);
     214        3566 :                 const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(nSVGTokenStyleIndex));
     215             : 
     216        3566 :                 parseAttribute(aTokenName, SVGTokenStyle, xAttribs->getValueByIndex(nSVGTokenStyleIndex));
     217       14325 :             }
     218       10759 :         }
     219             : 
     220           0 :         Display getDisplayFromContent(const rtl::OUString& aContent)
     221             :         {
     222           0 :             if(aContent.getLength())
     223             :             {
     224           0 :                 if(aContent.startsWith("inline"))
     225             :                 {
     226           0 :                     return Display_inline;
     227             :                 }
     228           0 :                 else if(aContent.startsWith("none"))
     229             :                 {
     230           0 :                     return Display_none;
     231             :                 }
     232           0 :                 else if(aContent.startsWith("inherit"))
     233             :                 {
     234           0 :                     return Display_inherit;
     235             :                 }
     236           0 :                 else if(aContent.startsWith("block"))
     237             :                 {
     238           0 :                     return Display_block;
     239             :                 }
     240           0 :                 else if(aContent.startsWith("list-item"))
     241             :                 {
     242           0 :                     return Display_list_item;
     243             :                 }
     244           0 :                 else if(aContent.startsWith("run-in"))
     245             :                 {
     246           0 :                     return Display_run_in;
     247             :                 }
     248           0 :                 else if(aContent.startsWith("compact"))
     249             :                 {
     250           0 :                     return Display_compact;
     251             :                 }
     252           0 :                 else if(aContent.startsWith("marker"))
     253             :                 {
     254           0 :                     return Display_marker;
     255             :                 }
     256           0 :                 else if(aContent.startsWith("table"))
     257             :                 {
     258           0 :                     return Display_table;
     259             :                 }
     260           0 :                 else if(aContent.startsWith("inline-table"))
     261             :                 {
     262           0 :                     return Display_inline_table;
     263             :                 }
     264           0 :                 else if(aContent.startsWith("table-row-group"))
     265             :                 {
     266           0 :                     return Display_table_row_group;
     267             :                 }
     268           0 :                 else if(aContent.startsWith("table-header-group"))
     269             :                 {
     270           0 :                     return Display_table_header_group;
     271             :                 }
     272           0 :                 else if(aContent.startsWith("table-footer-group"))
     273             :                 {
     274           0 :                     return Display_table_footer_group;
     275             :                 }
     276           0 :                 else if(aContent.startsWith("table-row"))
     277             :                 {
     278           0 :                     return Display_table_row;
     279             :                 }
     280           0 :                 else if(aContent.startsWith("table-column-group"))
     281             :                 {
     282           0 :                     return Display_table_column_group;
     283             :                 }
     284           0 :                 else if(aContent.startsWith("table-column"))
     285             :                 {
     286           0 :                     return Display_table_column;
     287             :                 }
     288           0 :                 else if(aContent.startsWith("table-cell"))
     289             :                 {
     290           0 :                     return Display_table_cell;
     291             :                 }
     292           0 :                 else if(aContent.startsWith("table-caption"))
     293             :                 {
     294           0 :                     return Display_table_caption;
     295             :                 }
     296             :             }
     297             : 
     298             :             // return the default
     299           0 :             return Display_inline;
     300             :         }
     301             : 
     302       29290 :         void SvgNode::parseAttribute(const OUString& /*rTokenName*/, SVGToken aSVGToken, const OUString& aContent)
     303             :         {
     304       29290 :             switch(aSVGToken)
     305             :             {
     306             :                 case SVGTokenId:
     307             :                 {
     308        2308 :                     if(!aContent.isEmpty())
     309             :                     {
     310        2308 :                         setId(&aContent);
     311             :                     }
     312        2308 :                     break;
     313             :                 }
     314             :                 case SVGTokenClass:
     315             :                 {
     316           0 :                     if(!aContent.isEmpty())
     317             :                     {
     318           0 :                         setClass(&aContent);
     319             :                     }
     320           0 :                     break;
     321             :                 }
     322             :                 case SVGTokenXmlSpace:
     323             :                 {
     324         292 :                     if(!aContent.isEmpty())
     325             :                     {
     326         292 :                         if(aContent.startsWith("default"))
     327             :                         {
     328           0 :                             setXmlSpace(XmlSpace_default);
     329             :                         }
     330         292 :                         else if(aContent.startsWith("preserve"))
     331             :                         {
     332         292 :                             setXmlSpace(XmlSpace_preserve);
     333             :                         }
     334             :                     }
     335         292 :                     break;
     336             :                 }
     337             :                 case SVGTokenDisplay:
     338             :                 {
     339           0 :                     if(aContent.getLength())
     340             :                     {
     341           0 :                         setDisplay(getDisplayFromContent(aContent));
     342             :                     }
     343           0 :                     break;
     344             :                 }
     345             :                 default:
     346             :                 {
     347       26690 :                     break;
     348             :                 }
     349             :             }
     350       29290 :         }
     351             : 
     352        7645 :         void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
     353             :         {
     354        7645 :             if(Display_none == getDisplay())
     355             :             {
     356           0 :                 return;
     357             :             }
     358             : 
     359        7645 :             if(!bReferenced)
     360             :             {
     361       19855 :                 if(SVGTokenDefs == getType() ||
     362       12842 :                     SVGTokenSymbol == getType() ||
     363       12749 :                     SVGTokenClipPathNode == getType() ||
     364       12467 :                     SVGTokenMask == getType() ||
     365       18995 :                     SVGTokenMarker == getType() ||
     366        6139 :                     SVGTokenPattern == getType())
     367             :                 {
     368             :                     // do not decompose defs or symbol nodes (these hold only style-like
     369             :                     // objects which may be used by referencing them) except when doing
     370             :                     // so controlled referenced
     371             : 
     372             :                     // also do not decompose ClipPaths and Masks. These should be embedded
     373             :                     // in a defs node (which gets not decomposed by itself), but you never
     374             :                     // know
     375             : 
     376             :                     // also not directly used are Markers and Patterns, only indirecty used
     377             :                     // by reference
     378             : 
     379             :                     // #i121656# also do not decompose nodes which have display="none" set
     380             :                     // as property
     381         578 :                     return;
     382             :                 }
     383             :             }
     384             : 
     385        7067 :             const SvgNodeVector& rChildren = getChildren();
     386             : 
     387        7067 :             if(!rChildren.empty())
     388             :             {
     389        3684 :                 const sal_uInt32 nCount(rChildren.size());
     390             : 
     391       13955 :                 for(sal_uInt32 a(0); a < nCount; a++)
     392             :                 {
     393       10271 :                     SvgNode* pCandidate = rChildren[a];
     394             : 
     395       10271 :                     if(pCandidate && Display_none != pCandidate->getDisplay())
     396             :                     {
     397       10271 :                         drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
     398             : 
     399       10271 :                         pCandidate->decomposeSvgNode(aNewTarget, bReferenced);
     400             : 
     401       10271 :                         if(aNewTarget.hasElements())
     402             :                         {
     403        5002 :                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget);
     404       10271 :                         }
     405             :                     }
     406             :                     else
     407             :                     {
     408             :                         OSL_ENSURE(false, "Null-Pointer in child node list (!)");
     409             :                     }
     410             :                 }
     411             : 
     412        3684 :                 if(rTarget.hasElements())
     413             :                 {
     414        2397 :                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
     415             : 
     416        2397 :                     if(pStyles)
     417             :                     {
     418             :                         // check if we have Title or Desc
     419        2397 :                         const OUString& rTitle = pStyles->getTitle();
     420        2397 :                         const OUString& rDesc = pStyles->getDesc();
     421             : 
     422        2397 :                         if(!rTitle.isEmpty() || !rDesc.isEmpty())
     423             :                         {
     424             :                             // default object name is empty
     425           0 :                             OUString aObjectName;
     426             : 
     427             :                             // use path as object name when outmost element
     428           0 :                             if(SVGTokenSvg == getType())
     429             :                             {
     430           0 :                                 aObjectName = getDocument().getAbsolutePath();
     431             : 
     432           0 :                                 if(!aObjectName.isEmpty())
     433             :                                 {
     434           0 :                                     INetURLObject aURL(aObjectName);
     435             : 
     436           0 :                                     aObjectName = aURL.getName(
     437             :                                         INetURLObject::LAST_SEGMENT,
     438             :                                         true,
     439           0 :                                         INetURLObject::DECODE_WITH_CHARSET);
     440             :                                 }
     441             :                             }
     442             : 
     443             :                             // pack in ObjectInfoPrimitive2D group
     444             :                             const drawinglayer::primitive2d::Primitive2DReference xRef(
     445             :                                 new drawinglayer::primitive2d::ObjectInfoPrimitive2D(
     446             :                                     rTarget,
     447             :                                     aObjectName,
     448             :                                     rTitle,
     449           0 :                                     rDesc));
     450             : 
     451           0 :                             rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
     452             :                         }
     453             :                     }
     454             :                 }
     455             :             }
     456             :         }
     457             : 
     458           0 :         const basegfx::B2DRange SvgNode::getCurrentViewPort() const
     459             :         {
     460           0 :             if(getParent())
     461             :             {
     462           0 :                 return getParent()->getCurrentViewPort();
     463             :             }
     464             :             else
     465             :             {
     466           0 :                 return basegfx::B2DRange(); // return empty B2DRange
     467             :             }
     468             :         }
     469             : 
     470           0 :         double SvgNode::getCurrentFontSizeInherited() const
     471             :         {
     472           0 :             if(getParent())
     473             :             {
     474           0 :                 return getParent()->getCurrentFontSize();
     475             :             }
     476             :             else
     477             :             {
     478           0 :                 return 0.0;
     479             :             }
     480             :         }
     481             : 
     482           0 :         double SvgNode::getCurrentFontSize() const
     483             :         {
     484           0 :             if(getSvgStyleAttributes())
     485           0 :                 return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate);
     486             : 
     487           0 :             return getCurrentFontSizeInherited();
     488             :         }
     489             : 
     490           0 :         double SvgNode::getCurrentXHeightInherited() const
     491             :         {
     492           0 :             if(getParent())
     493             :             {
     494           0 :                 return getParent()->getCurrentXHeight();
     495             :             }
     496             :             else
     497             :             {
     498           0 :                 return 0.0;
     499             :             }
     500             :         }
     501             : 
     502           0 :         double SvgNode::getCurrentXHeight() const
     503             :         {
     504           0 :             if(getSvgStyleAttributes())
     505             :                 // for XHeight, use FontSize currently
     506           0 :                 return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate);
     507             : 
     508           0 :             return getCurrentXHeightInherited();
     509             :         }
     510             : 
     511        2308 :         void SvgNode::setId(const OUString* pfId)
     512             :         {
     513        2308 :             if(mpId)
     514             :             {
     515           0 :                 mrDocument.removeSvgNodeFromMapper(*mpId);
     516           0 :                 delete mpId;
     517           0 :                 mpId = 0;
     518             :             }
     519             : 
     520        2308 :             if(pfId)
     521             :             {
     522        2308 :                 mpId = new OUString(*pfId);
     523        2308 :                 mrDocument.addSvgNodeToMapper(*mpId, *this);
     524             :             }
     525        2308 :         }
     526             : 
     527           0 :         void SvgNode::setClass(const OUString* pfClass)
     528             :         {
     529           0 :             if(mpClass)
     530             :             {
     531           0 :                 mrDocument.removeSvgNodeFromMapper(*mpClass);
     532           0 :                 delete mpClass;
     533           0 :                 mpClass = 0;
     534             :             }
     535             : 
     536           0 :             if(pfClass)
     537             :             {
     538           0 :                 mpClass = new OUString(*pfClass);
     539           0 :                 mrDocument.addSvgNodeToMapper(*mpClass, *this);
     540             :             }
     541           0 :         }
     542             : 
     543           0 :         XmlSpace SvgNode::getXmlSpace() const
     544             :         {
     545           0 :             if(maXmlSpace != XmlSpace_notset)
     546             :             {
     547           0 :                 return maXmlSpace;
     548             :             }
     549             : 
     550           0 :             if(getParent())
     551             :             {
     552           0 :                 return getParent()->getXmlSpace();
     553             :             }
     554             : 
     555             :             // default is XmlSpace_default
     556           0 :             return XmlSpace_default;
     557             :         }
     558             : 
     559             :     } // end of namespace svgreader
     560             : } // end of namespace svgio
     561             : 
     562             : 
     563             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10