LCOV - code coverage report
Current view: top level - svgio/source/svgreader - svgsvgnode.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 81 237 34.2 %
Date: 2014-04-11 Functions: 6 9 66.7 %
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 <svgio/svgreader/svgsvgnode.hxx>
      21             : #include <drawinglayer/geometry/viewinformation2d.hxx>
      22             : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
      23             : #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
      24             : #include <basegfx/polygon/b2dpolygontools.hxx>
      25             : #include <basegfx/polygon/b2dpolygon.hxx>
      26             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      27             : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
      28             : #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
      29             : 
      30             : 
      31             : 
      32             : namespace svgio
      33             : {
      34             :     namespace svgreader
      35             :     {
      36         292 :         SvgSvgNode::SvgSvgNode(
      37             :             SvgDocument& rDocument,
      38             :             SvgNode* pParent)
      39             :         :   SvgNode(SVGTokenSvg, rDocument, pParent),
      40             :             maSvgStyleAttributes(*this),
      41             :             mpViewBox(0),
      42             :             maSvgAspectRatio(),
      43             :             maX(),
      44             :             maY(),
      45             :             maWidth(),
      46             :             maHeight(),
      47         292 :             maVersion()
      48             :         {
      49         292 :             if(!getParent())
      50             :             {
      51             :                 // initial fill is black
      52         292 :                 maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
      53             :             }
      54         292 :         }
      55             : 
      56         876 :         SvgSvgNode::~SvgSvgNode()
      57             :         {
      58         292 :             if(mpViewBox) delete mpViewBox;
      59         584 :         }
      60             : 
      61       28279 :         const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
      62             :         {
      63       28279 :             return checkForCssStyle(OUString("svg"), maSvgStyleAttributes);
      64             :         }
      65             : 
      66        3023 :         void SvgSvgNode::parseAttribute(const OUString& rTokenName, SVGToken aSVGToken, const OUString& aContent)
      67             :         {
      68             :             // call parent
      69        3023 :             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
      70             : 
      71             :             // read style attributes
      72        3023 :             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
      73             : 
      74             :             // parse own
      75        3023 :             switch(aSVGToken)
      76             :             {
      77             :                 case SVGTokenStyle:
      78             :                 {
      79          12 :                     maSvgStyleAttributes.readStyle(aContent);
      80          12 :                     break;
      81             :                 }
      82             :                 case SVGTokenViewBox:
      83             :                 {
      84         292 :                     const basegfx::B2DRange aRange(readViewBox(aContent, *this));
      85             : 
      86         292 :                     if(!aRange.isEmpty())
      87             :                     {
      88         292 :                         setViewBox(&aRange);
      89             :                     }
      90         292 :                     break;
      91             :                 }
      92             :                 case SVGTokenPreserveAspectRatio:
      93             :                 {
      94           0 :                     setSvgAspectRatio(readSvgAspectRatio(aContent));
      95           0 :                     break;
      96             :                 }
      97             :                 case SVGTokenX:
      98             :                 {
      99           0 :                     SvgNumber aNum;
     100             : 
     101           0 :                     if(readSingleNumber(aContent, aNum))
     102             :                     {
     103           0 :                         setX(aNum);
     104             :                     }
     105           0 :                     break;
     106             :                 }
     107             :                 case SVGTokenY:
     108             :                 {
     109           0 :                     SvgNumber aNum;
     110             : 
     111           0 :                     if(readSingleNumber(aContent, aNum))
     112             :                     {
     113           0 :                         setY(aNum);
     114             :                     }
     115           0 :                     break;
     116             :                 }
     117             :                 case SVGTokenWidth:
     118             :                 {
     119         292 :                     SvgNumber aNum;
     120             : 
     121         292 :                     if(readSingleNumber(aContent, aNum))
     122             :                     {
     123         292 :                         if(aNum.isPositive())
     124             :                         {
     125         292 :                             setWidth(aNum);
     126             :                         }
     127             :                     }
     128         292 :                     break;
     129             :                 }
     130             :                 case SVGTokenHeight:
     131             :                 {
     132         292 :                     SvgNumber aNum;
     133             : 
     134         292 :                     if(readSingleNumber(aContent, aNum))
     135             :                     {
     136         292 :                         if(aNum.isPositive())
     137             :                         {
     138         292 :                             setHeight(aNum);
     139             :                         }
     140             :                     }
     141         292 :                     break;
     142             :                 }
     143             :                 case SVGTokenVersion:
     144             :                 {
     145         292 :                     SvgNumber aNum;
     146             : 
     147         292 :                     if(readSingleNumber(aContent, aNum))
     148             :                     {
     149         292 :                         setVersion(aNum);
     150             :                     }
     151         292 :                     break;
     152             :                 }
     153             :                 default:
     154             :                 {
     155        1843 :                     break;
     156             :                 }
     157             :             }
     158        3023 :         }
     159             : 
     160           0 :         void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const
     161             :         {
     162           0 :             if (!getParent() || bHasFound)
     163             :             {
     164           0 :                 return;
     165             :             }
     166           0 :             const SvgSvgNode* pParentSvgSvgNode = 0;
     167             :             // enclosing svg might have relative width, need to cumulate them till they are
     168             :             // resolved somewhere up in the node tree
     169           0 :             double fPercentage(1.0);
     170           0 :             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
     171             :             {
     172             :                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
     173           0 :                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
     174           0 :                 if (pParentSvgSvgNode)
     175             :                 {
     176           0 :                     if (pParentSvgSvgNode->getViewBox())
     177             :                     {
     178             :                         // viewbox values are already in 'user unit'.
     179           0 :                         fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage;
     180           0 :                         bHasFound = true;
     181             :                     }
     182             :                     else
     183             :                     {
     184             :                         // take absolute value or cummulate percentage
     185           0 :                         if (pParentSvgSvgNode->getWidth().isSet())
     186             :                         {
     187           0 :                             if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit())
     188             :                             {
     189           0 :                                 fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01;
     190             :                             }
     191             :                             else
     192             :                             {
     193           0 :                                 fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
     194           0 :                                 bHasFound = true;
     195             :                             }
     196             :                         } // not set => width=100% => factor 1, no need for else
     197             :                     }
     198             :                 }
     199             :             }
     200             :         }
     201             : 
     202           0 :         void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const
     203             :         {
     204           0 :             if (!getParent() || bHasFound)
     205             :             {
     206           0 :                 return;
     207             :             }
     208           0 :             const SvgSvgNode* pParentSvgSvgNode = 0;
     209             :             // enclosing svg might have relative width and height, need to cumulate them till they are
     210             :             // resolved somewhere up in the node tree
     211           0 :             double fPercentage(1.0);
     212           0 :             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
     213             :             {
     214             :                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
     215           0 :                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
     216           0 :                 if (pParentSvgSvgNode)
     217             :                 {
     218           0 :                     if (pParentSvgSvgNode->getViewBox())
     219             :                     {
     220             :                         // viewbox values are already in 'user unit'.
     221           0 :                         fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage;
     222           0 :                         bHasFound = true;
     223             :                     }
     224             :                     else
     225             :                     {
     226             :                         // take absolute value or cummulate percentage
     227           0 :                         if (pParentSvgSvgNode->getHeight().isSet())
     228             :                         {
     229           0 :                             if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit())
     230             :                             {
     231           0 :                                 fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01;
     232             :                             }
     233             :                             else
     234             :                             {
     235           0 :                                 fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
     236           0 :                                 bHasFound = true;
     237             :                             }
     238             :                         } // not set => height=100% => factor 1, no need for else
     239             :                     }
     240             :                 }
     241             :             }
     242             :         }
     243             : 
     244             : // ToDo: Consider attribute overflow in method decomposeSvgNode
     245         292 :         void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
     246             :         {
     247         292 :             drawinglayer::primitive2d::Primitive2DSequence aSequence;
     248             : 
     249             :             // decompose children
     250         292 :             SvgNode::decomposeSvgNode(aSequence, bReferenced);
     251             : 
     252         292 :             if(aSequence.hasElements())
     253             :             {
     254         292 :                 if(getParent())
     255             :                 {
     256             :                     // #i122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec).
     257             :                     // If it is relative, the question is to what. The previous implementatin assumed relative to the
     258             :                     // local ViewBox which is implied by (4.2 Basic data types):
     259             : 
     260             :                     // "Note that the non-property <length> definition also allows a percentage unit identifier.
     261             :                     // The meaning of a percentage length value depends on the attribute for which the percentage
     262             :                     // length value has been specified. Two common cases are: (a) when a percentage length value
     263             :                     // represents a percentage of the viewport width or height (refer to the section that discusses
     264             :                     // units in general), and (b) when a percentage length value represents a percentage of the
     265             :                     // bounding box width or height on a given object (refer to the section that describes object
     266             :                     // bounding box units)."
     267             : 
     268             :                     // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport
     269             :                     // of the parent, and so does the new implementation.
     270             : 
     271             :                     // Extract known viewport data
     272             :                     // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
     273             : 
     274             :                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
     275             :                     // value 0.0 here is only to initialize variable
     276           0 :                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
     277           0 :                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
     278             : 
     279           0 :                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
     280           0 :                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
     281             : 
     282             :                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
     283           0 :                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
     284           0 :                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
     285             : 
     286           0 :                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
     287           0 :                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
     288             : 
     289           0 :                     if ( !bXIsAbsolute || !bWidthIsAbsolute)
     290             :                     {
     291             :                         // get width of enclosing svg and resolve percentage in x and width;
     292           0 :                         double fWReference(0.0);
     293           0 :                         bool bHasFoundWidth(false);
     294           0 :                         seekReferenceWidth(fWReference, bHasFoundWidth);
     295           0 :                         if (!bHasFoundWidth)
     296             :                         {
     297             :                             // Even outermost svg has not all information to resolve relative values,
     298             :                             // I use content itself as fallback to set missing values for viewport
     299             :                             // Any better idea for such ill structures svg documents?
     300             :                             const basegfx::B2DRange aChildRange(
     301             :                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
     302             :                                             aSequence,
     303           0 :                                         drawinglayer::geometry::ViewInformation2D()));
     304           0 :                             fWReference = aChildRange.getWidth();
     305             :                         }
     306             :                         // referenced values are already in 'user unit'
     307           0 :                         if (!bXIsAbsolute)
     308             :                         {
     309           0 :                             fX = getX().getNumber() * 0.01 * fWReference;
     310             :                         }
     311           0 :                         if (!bWidthIsAbsolute)
     312             :                         {
     313           0 :                             fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
     314             :                         }
     315             :                     }
     316             : 
     317           0 :                     if ( !bYIsAbsolute || !bHeightIsAbsolute)
     318             :                     {
     319             :                         // get height of enclosing svg and resolve percentage in y and height
     320           0 :                         double fHReference(0.0);
     321           0 :                         bool bHasFoundHeight(false);
     322           0 :                         seekReferenceHeight(fHReference, bHasFoundHeight);
     323           0 :                         if (!bHasFoundHeight)
     324             :                         {
     325             :                             // Even outermost svg has not all information to resolve relative values,
     326             :                             // I use content itself as fallback to set missing values for viewport
     327             :                             // Any better idea for such ill structures svg documents?
     328             :                             const basegfx::B2DRange aChildRange(
     329             :                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
     330             :                                             aSequence,
     331           0 :                                         drawinglayer::geometry::ViewInformation2D()));
     332           0 :                             fHReference = aChildRange.getHeight();
     333             :                         }
     334             : 
     335             :                         // referenced values are already in 'user unit'
     336           0 :                         if (!bYIsAbsolute)
     337             :                         {
     338           0 :                             fY = getY().getNumber() * 0.01 * fHReference;
     339             :                         }
     340           0 :                         if (!bHeightIsAbsolute)
     341             :                         {
     342           0 :                             fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
     343             :                         }
     344             :                     }
     345             : 
     346           0 :                     if(getViewBox())
     347             :                     {
     348             :                         // SVG 1.1 defines in section 7.7 that a negative value for width or height
     349             :                         // in viewBox is an error and that 0.0 disables rendering
     350           0 :                         if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0))
     351             :                         {
     352             :                             // create target range homing x,y, width and height as calculated above
     353           0 :                             const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
     354             : 
     355           0 :                             if(aTarget.equal(*getViewBox()))
     356             :                             {
     357             :                                 // no mapping needed, append
     358           0 :                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
     359             :                             }
     360             :                             else
     361             :                             {
     362             :                                 // create mapping
     363             :                                 // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
     364             :                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
     365           0 :                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
     366           0 :                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
     367             : 
     368             :                                 // let mapping be created from SvgAspectRatio
     369             :                                 const basegfx::B2DHomMatrix aEmbeddingTransform(
     370           0 :                                     rRatio.createMapping(aTarget, *getViewBox()));
     371             : 
     372             :                                 // prepare embedding in transformation
     373             :                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
     374             :                                     new drawinglayer::primitive2d::TransformPrimitive2D(
     375             :                                         aEmbeddingTransform,
     376           0 :                                         aSequence));
     377             : 
     378           0 :                                 if(rRatio.isMeetOrSlice())
     379             :                                 {
     380             :                                     // embed in transformation
     381           0 :                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
     382             :                                 }
     383             :                                 else
     384             :                                 {
     385             :                                     // need to embed in MaskPrimitive2D, too
     386             :                                     const drawinglayer::primitive2d::Primitive2DReference xMask(
     387             :                                         new drawinglayer::primitive2d::MaskPrimitive2D(
     388             :                                             basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
     389           0 :                                             drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
     390             : 
     391           0 :                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
     392           0 :                                 }
     393             :                             }
     394             :                         }
     395             :                     }
     396             :                     else // no viewBox attribute
     397             :                     {
     398             :                         // Svg defines that a negative value is an error and that 0.0 disables rendering
     399           0 :                         if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
     400             :                         {
     401           0 :                             if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
     402             :                             {
     403             :                                 // embed in transform
     404             :                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
     405             :                                     new drawinglayer::primitive2d::TransformPrimitive2D(
     406             :                                         basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
     407           0 :                                         aSequence));
     408             : 
     409           0 :                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
     410             :                             }
     411             : 
     412             :                             // embed in MaskPrimitive2D to clip
     413             :                             const drawinglayer::primitive2d::Primitive2DReference xMask(
     414             :                                 new drawinglayer::primitive2d::MaskPrimitive2D(
     415             :                                     basegfx::B2DPolyPolygon(
     416             :                                         basegfx::tools::createPolygonFromRect(
     417             :                                             basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
     418           0 :                                     aSequence));
     419             : 
     420             :                             // append
     421           0 :                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
     422             :                         }
     423             :                     }
     424             :                 }
     425             :                 else // Outermost SVG element
     426             :                 {
     427         292 :                     double fW = 0.0; // effective value depends on viewBox
     428         292 :                     double fH = 0.0;
     429             : 
     430             :                     // Svg defines that a negative value is an error and that 0.0 disables rendering
     431             :                     // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive'
     432         292 :                     const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0));
     433         292 :                     const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0));
     434         292 :                     if(!bWidthInvalid && !bHeightInvalid)
     435             :                     {
     436         292 :                         basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox
     437         292 :                         if(getViewBox())
     438             :                         {
     439             :                             // SVG 1.1 defines in section 7.7 that a negative value for width or height
     440             :                             // in viewBox is an error and that 0.0 disables rendering
     441         292 :                             const double fViewBoxWidth = getViewBox()->getWidth();
     442         292 :                             const double fViewBoxHeight = getViewBox()->getHeight();
     443         292 :                             if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0))
     444             :                             {
     445             :                                 // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height
     446             :                                 // or if one or both of them is relative by the width and height of the viewBox
     447             :                                 // see SVG 1.1 section 7.12
     448         292 :                                 const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
     449         292 :                                 const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
     450         292 :                                 if(bWidthIsAbsolute && bHeightIsAbsolute)
     451             :                                 {
     452         292 :                                     fW =getWidth().solveNonPercentage(*this);
     453         292 :                                     fH =getHeight().solveNonPercentage(*this);
     454             :                                 }
     455           0 :                                 else if (bWidthIsAbsolute)
     456             :                                 {
     457           0 :                                     fW = getWidth().solveNonPercentage(*this);
     458           0 :                                     fH = fW * fViewBoxWidth / fViewBoxHeight ;
     459             :                                 }
     460           0 :                                 else if (bHeightIsAbsolute)
     461             :                                 {
     462           0 :                                     fH = getHeight().solveNonPercentage(*this);
     463           0 :                                     fW = fH * fViewBoxWidth / fViewBoxHeight ;
     464             :                                 }
     465             :                                 else
     466             :                                 {
     467           0 :                                     fW = fViewBoxWidth;
     468           0 :                                     fH = fViewBoxHeight;
     469             :                                 }
     470             :                                 // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
     471         292 :                                 aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
     472             : 
     473             :                                 // create mapping
     474             :                                 // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
     475             :                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
     476         292 :                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
     477         292 :                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
     478             : 
     479         292 :                                 basegfx::B2DHomMatrix aViewBoxMapping;
     480         292 :                                 aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
     481             :                                 // no need to check ratio here for slice, the outermost Svg will
     482             :                                 // be clipped anyways (see below)
     483             : 
     484             :                                 // scale content to viewBox definitions
     485             :                                 const drawinglayer::primitive2d::Primitive2DReference xTransform(
     486             :                                     new drawinglayer::primitive2d::TransformPrimitive2D(
     487             :                                         aViewBoxMapping,
     488         584 :                                         aSequence));
     489             : 
     490         584 :                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
     491             :                             }
     492             :                         }
     493             :                         else // no viewbox
     494             :                         {
     495             :                            // There exists no parent to resolve relative width or height.
     496             :                            // Use child size as fallback.
     497           0 :                             const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
     498           0 :                             const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
     499           0 :                             if (bWidthIsAbsolute && bHeightIsAbsolute)
     500             :                             {
     501           0 :                                 fW =getWidth().solveNonPercentage(*this);
     502           0 :                                 fH =getHeight().solveNonPercentage(*this);
     503             : 
     504             :                             }
     505             :                             else
     506             :                             {
     507             :                                 const basegfx::B2DRange aChildRange(
     508             :                                     drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
     509             :                                         aSequence,
     510           0 :                                      drawinglayer::geometry::ViewInformation2D()));
     511           0 :                                 const double fChildWidth(aChildRange.getWidth());
     512           0 :                                 const double fChildHeight(aChildRange.getHeight());
     513           0 :                                 fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth;
     514           0 :                                 fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight;
     515             :                             }
     516             :                             // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
     517           0 :                             aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
     518             :                         }
     519             : 
     520             :                         // to be completely correct in Svg sense it is necessary to clip
     521             :                         // the whole content to the given canvas. I choose here to do this
     522             :                         // initially despite I found various examples of Svg files out there
     523             :                         // which have no correct values for this clipping. It's correct
     524             :                         // due to the Svg spec.
     525         292 :                         bool bDoCorrectCanvasClipping(true);
     526             : 
     527         292 :                         if(bDoCorrectCanvasClipping)
     528             :                         {
     529             :                             // different from Svg we have the possibility with primitives to get
     530             :                             // a correct bounding box for the geometry. Get it for evtl. taking action
     531             :                             const basegfx::B2DRange aContentRange(
     532             :                                 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
     533             :                                     aSequence,
     534         292 :                                     drawinglayer::geometry::ViewInformation2D()));
     535             : 
     536         292 :                             if(aSvgCanvasRange.isInside(aContentRange))
     537             :                             {
     538             :                                 // no clip needed, but an invisible HiddenGeometryPrimitive2D
     539             :                                 // to allow getting the full Svg range using the primitive mechanisms.
     540             :                                 // This is needed since e.g. an SdrObject using this as graphic will
     541             :                                 // create a mapping transformation to exactly map the content to it's
     542             :                                 // real life size
     543             :                                 const drawinglayer::primitive2d::Primitive2DReference xLine(
     544             :                                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
     545             :                                         basegfx::tools::createPolygonFromRect(
     546             :                                             aSvgCanvasRange),
     547         211 :                                         basegfx::BColor(0.0, 0.0, 0.0)));
     548             :                                 const drawinglayer::primitive2d::Primitive2DReference xHidden(
     549             :                                     new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
     550         422 :                                         drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
     551             : 
     552         422 :                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
     553             :                             }
     554          81 :                             else if(aSvgCanvasRange.overlaps(aContentRange))
     555             :                             {
     556             :                                 // Clip is necessary. This will make Svg images evtl. smaller
     557             :                                 // than wanted from Svg (the free space which may be around it is
     558             :                                 // conform to the Svg spec), but avoids an expensive and unnecessary
     559             :                                 // clip. Keep the full Svg range here to get the correct mappings
     560             :                                 // to objects using this. Optimizations can be done in the processors
     561             :                                 const drawinglayer::primitive2d::Primitive2DReference xMask(
     562             :                                     new drawinglayer::primitive2d::MaskPrimitive2D(
     563             :                                         basegfx::B2DPolyPolygon(
     564             :                                             basegfx::tools::createPolygonFromRect(
     565             :                                                 aSvgCanvasRange)),
     566          81 :                                         aSequence));
     567             : 
     568          81 :                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
     569             :                             }
     570             :                             else
     571             :                             {
     572             :                                 // not inside, no overlap. Empty Svg
     573           0 :                                 aSequence.realloc(0);
     574             :                             }
     575             :                         }
     576             : 
     577         292 :                         if(aSequence.hasElements())
     578             :                         {
     579             :                             // embed in transform primitive to scale to 1/100th mm
     580             :                             // where 1 inch == 25.4 mm to get from Svg coordinates (px) to
     581             :                             // drawinglayer coordinates
     582         292 :                             const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH);
     583             :                             const basegfx::B2DHomMatrix aTransform(
     584             :                                 basegfx::tools::createScaleB2DHomMatrix(
     585             :                                     fScaleTo100thmm,
     586         292 :                                     fScaleTo100thmm));
     587             : 
     588             :                             const drawinglayer::primitive2d::Primitive2DReference xTransform(
     589             :                                 new drawinglayer::primitive2d::TransformPrimitive2D(
     590             :                                     aTransform,
     591         584 :                                     aSequence));
     592             : 
     593         292 :                             aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
     594             : 
     595             :                             // append to result
     596         584 :                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
     597             :                         }
     598             :                     }
     599             :                 }
     600         292 :             }
     601         292 :         }
     602             : 
     603           0 :         const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const
     604             :         {
     605           0 :             if(getViewBox())
     606             :             {
     607           0 :                 return *(getViewBox());
     608             :             }
     609             :             else // viewport should be given by x, y, width, and height
     610             :             {
     611             :                 // Extract known viewport data
     612             :                 // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
     613           0 :                 if (getParent())
     614             :                     {
     615             :                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
     616             :                     // value 0.0 here is only to initialize variable
     617           0 :                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
     618           0 :                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
     619           0 :                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
     620           0 :                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
     621             : 
     622             :                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
     623           0 :                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
     624           0 :                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
     625             : 
     626           0 :                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
     627           0 :                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
     628             : 
     629           0 :                     if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
     630             :                     {
     631           0 :                         return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
     632             :                     }
     633             :                     else // try to resolve relative values
     634             :                     {
     635           0 :                         if (!bXIsAbsolute || !bWidthIsAbsolute)
     636             :                         {
     637             :                             // get width of enclosing svg and resolve percentage in x and width
     638           0 :                             double fWReference(0.0);
     639           0 :                             bool bHasFoundWidth(false);
     640           0 :                             seekReferenceWidth(fWReference, bHasFoundWidth);
     641             :                             // referenced values are already in 'user unit'
     642           0 :                             if (!bXIsAbsolute && bHasFoundWidth)
     643             :                             {
     644           0 :                                 fX = getX().getNumber() * 0.01 * fWReference;
     645           0 :                                 bXIsAbsolute = true;
     646             :                             }
     647           0 :                             if (!bWidthIsAbsolute && bHasFoundWidth)
     648             :                             {
     649           0 :                                 fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
     650           0 :                                 bWidthIsAbsolute = true;
     651             :                             }
     652             :                         }
     653           0 :                         if (!bYIsAbsolute || !bHeightIsAbsolute)
     654             :                         {
     655             :                             // get height of enclosing svg and resolve percentage in y and height
     656           0 :                             double fHReference(0.0);
     657           0 :                             bool bHasFoundHeight(false);
     658           0 :                             seekReferenceHeight(fHReference, bHasFoundHeight);
     659             :                             // referenced values are already in 'user unit'
     660           0 :                             if (!bYIsAbsolute && bHasFoundHeight)
     661             :                             {
     662           0 :                                 fY = getY().getNumber() * 0.01 * fHReference;
     663           0 :                                 bYIsAbsolute = true;
     664             :                             }
     665           0 :                             if (!bHeightIsAbsolute && bHasFoundHeight)
     666             :                             {
     667           0 :                                 fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
     668           0 :                                 bHeightIsAbsolute = true;
     669             :                             }
     670             :                         }
     671             : 
     672           0 :                         if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
     673             :                         {
     674           0 :                             return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
     675             :                         }
     676             :                         else // relative values could not be resolved, there exists no fallback
     677             :                         {
     678           0 :                             return SvgNode::getCurrentViewPort();
     679             :                         }
     680             :                     }
     681             :                 }
     682             :                 else //outermost svg
     683             :                 {
     684             :                     // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2
     685             :                     // But here it cannot be resolved and no fallback exists.
     686             :                     // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
     687           0 :                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
     688           0 :                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
     689           0 :                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
     690           0 :                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
     691           0 :                     if (bWidthIsAbsolute && bHeightIsAbsolute)
     692             :                     {
     693           0 :                         return basegfx::B2DRange(0.0, 0.0, fW, fH);
     694             :                     }
     695             :                     else // no fallback exists
     696             :                     {
     697           0 :                             return SvgNode::getCurrentViewPort();
     698             :                     }
     699             :                 }
     700             : // ToDo: Is it possible to decompose and use the bounding box of the children, if even the
     701             : //       outermost svg has no information to resolve percentage? Is it worth, how expensive is it?
     702             : 
     703             :             }
     704             :         }
     705             : 
     706             :     } // end of namespace svgreader
     707             : } // end of namespace svgio
     708             : 
     709             : 
     710             : // eof
     711             : 
     712             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10