1ddde725dSArmin Le Grand /************************************************************** 2ddde725dSArmin Le Grand * 3ddde725dSArmin Le Grand * Licensed to the Apache Software Foundation (ASF) under one 4ddde725dSArmin Le Grand * or more contributor license agreements. See the NOTICE file 5ddde725dSArmin Le Grand * distributed with this work for additional information 6ddde725dSArmin Le Grand * regarding copyright ownership. The ASF licenses this file 7ddde725dSArmin Le Grand * to you under the Apache License, Version 2.0 (the 8ddde725dSArmin Le Grand * "License"); you may not use this file except in compliance 9ddde725dSArmin Le Grand * with the License. You may obtain a copy of the License at 10ddde725dSArmin Le Grand * 11ddde725dSArmin Le Grand * http://www.apache.org/licenses/LICENSE-2.0 12ddde725dSArmin Le Grand * 13ddde725dSArmin Le Grand * Unless required by applicable law or agreed to in writing, 14ddde725dSArmin Le Grand * software distributed under the License is distributed on an 15ddde725dSArmin Le Grand * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16ddde725dSArmin Le Grand * KIND, either express or implied. See the License for the 17ddde725dSArmin Le Grand * specific language governing permissions and limitations 18ddde725dSArmin Le Grand * under the License. 19ddde725dSArmin Le Grand * 20ddde725dSArmin Le Grand *************************************************************/ 21ddde725dSArmin Le Grand 22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove 23ddde725dSArmin Le Grand #include "precompiled_svgio.hxx" 24ddde725dSArmin Le Grand 25ddde725dSArmin Le Grand #include <svgio/svgreader/svgsvgnode.hxx> 26ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx> 27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx> 28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx> 29ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx> 30ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx> 31ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx> 3241923119SArmin Le Grand #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 3341923119SArmin Le Grand #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx> 34ddde725dSArmin Le Grand 35ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 36ddde725dSArmin Le Grand 37ddde725dSArmin Le Grand namespace svgio 38ddde725dSArmin Le Grand { 39ddde725dSArmin Le Grand namespace svgreader 40ddde725dSArmin Le Grand { SvgSvgNode(SvgDocument & rDocument,SvgNode * pParent)41ddde725dSArmin Le Grand SvgSvgNode::SvgSvgNode( 42ddde725dSArmin Le Grand SvgDocument& rDocument, 43ddde725dSArmin Le Grand SvgNode* pParent) 44ddde725dSArmin Le Grand : SvgNode(SVGTokenSvg, rDocument, pParent), 45ddde725dSArmin Le Grand maSvgStyleAttributes(*this), 46ddde725dSArmin Le Grand mpViewBox(0), 47ddde725dSArmin Le Grand maSvgAspectRatio(), 48ddde725dSArmin Le Grand maX(), 49ddde725dSArmin Le Grand maY(), 50ddde725dSArmin Le Grand maWidth(), 51ddde725dSArmin Le Grand maHeight(), 524374d266SArmin Le Grand maVersion(), 534374d266SArmin Le Grand mbStyleAttributesInitialized(false) // #125258# 54ddde725dSArmin Le Grand { 554374d266SArmin Le Grand } 564374d266SArmin Le Grand 574374d266SArmin Le Grand // #125258# initializeStyleAttributes()584374d266SArmin Le Grand void SvgSvgNode::initializeStyleAttributes() 594374d266SArmin Le Grand { 604374d266SArmin Le Grand if(!mbStyleAttributesInitialized) 61ddde725dSArmin Le Grand { 624374d266SArmin Le Grand // #125258# determine if initial values need to be initialized with hard values 634374d266SArmin Le Grand // for the case that this is the outmost SVG statement and it has no parent 644374d266SArmin Le Grand // stale (CssStyle for svg may be defined) 654374d266SArmin Le Grand bool bSetInitialValues(true); 664374d266SArmin Le Grand 674374d266SArmin Le Grand if(getParent()) 684374d266SArmin Le Grand { 694374d266SArmin Le Grand // #125258# no initial values when it's a SVG element embedded in SVG 704374d266SArmin Le Grand bSetInitialValues = false; 714374d266SArmin Le Grand } 724374d266SArmin Le Grand 734374d266SArmin Le Grand if(bSetInitialValues) 744374d266SArmin Le Grand { 754374d266SArmin Le Grand const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); 764374d266SArmin Le Grand 774374d266SArmin Le Grand if(pStyles && pStyles->getParentStyle()) 784374d266SArmin Le Grand { 799d01bcdeSArmin Le Grand // SVG has a parent style (probably CssStyle), check if fill is set there anywhere 809d01bcdeSArmin Le Grand // already. If yes, do not set the default fill (black) 819d01bcdeSArmin Le Grand bool bFillSet(false); 829d01bcdeSArmin Le Grand const SvgStyleAttributes* pParentStyle = pStyles->getParentStyle(); 839d01bcdeSArmin Le Grand 849d01bcdeSArmin Le Grand while(pParentStyle && !bFillSet) 859d01bcdeSArmin Le Grand { 869d01bcdeSArmin Le Grand bFillSet = pParentStyle->isFillSet(); 879d01bcdeSArmin Le Grand pParentStyle = pParentStyle->getParentStyle(); 889d01bcdeSArmin Le Grand } 899d01bcdeSArmin Le Grand 909d01bcdeSArmin Le Grand if(bFillSet) 919d01bcdeSArmin Le Grand { 929d01bcdeSArmin Le Grand // #125258# no initial values when SVG has a parent style at which a fill 939d01bcdeSArmin Le Grand // is already set 949d01bcdeSArmin Le Grand bSetInitialValues = false; 959d01bcdeSArmin Le Grand } 964374d266SArmin Le Grand } 974374d266SArmin Le Grand } 984374d266SArmin Le Grand 994374d266SArmin Le Grand if(bSetInitialValues) 1004374d266SArmin Le Grand { 1014374d266SArmin Le Grand // #125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done, 1024374d266SArmin Le Grand // just setting may revert an already set valid value) 1034374d266SArmin Le Grand if(!maSvgStyleAttributes.isFillSet()) 1044374d266SArmin Le Grand { 1054374d266SArmin Le Grand // #125258# initial fill is black (see SVG1.1 spec) 1064374d266SArmin Le Grand maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); 1074374d266SArmin Le Grand } 1084374d266SArmin Le Grand } 1094374d266SArmin Le Grand 1104374d266SArmin Le Grand mbStyleAttributesInitialized = true; 111ddde725dSArmin Le Grand } 112ddde725dSArmin Le Grand } 113ddde725dSArmin Le Grand ~SvgSvgNode()114ddde725dSArmin Le Grand SvgSvgNode::~SvgSvgNode() 115ddde725dSArmin Le Grand { 116ddde725dSArmin Le Grand if(mpViewBox) delete mpViewBox; 117ddde725dSArmin Le Grand } 118ddde725dSArmin Le Grand getSvgStyleAttributes() const119ddde725dSArmin Le Grand const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const 120ddde725dSArmin Le Grand { 1214374d266SArmin Le Grand // #125258# svg node can vahe CssStyles, too, so check for it here 1224374d266SArmin Le Grand static rtl::OUString aClassStr(rtl::OUString::createFromAscii("svg")); 1234374d266SArmin Le Grand 1244374d266SArmin Le Grand return checkForCssStyle(aClassStr, maSvgStyleAttributes); 125ddde725dSArmin Le Grand } 126ddde725dSArmin Le Grand parseAttribute(const rtl::OUString & rTokenName,SVGToken aSVGToken,const rtl::OUString & aContent)127ddde725dSArmin Le Grand void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 128ddde725dSArmin Le Grand { 129ddde725dSArmin Le Grand // call parent 130ddde725dSArmin Le Grand SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 131ddde725dSArmin Le Grand 132ddde725dSArmin Le Grand // read style attributes 133*52cb04b8SArmin Le Grand maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent, false); 134ddde725dSArmin Le Grand 135ddde725dSArmin Le Grand // parse own 136ddde725dSArmin Le Grand switch(aSVGToken) 137ddde725dSArmin Le Grand { 138ddde725dSArmin Le Grand case SVGTokenStyle: 139ddde725dSArmin Le Grand { 1409d01bcdeSArmin Le Grand readLocalCssStyle(aContent); 141ddde725dSArmin Le Grand break; 142ddde725dSArmin Le Grand } 143ddde725dSArmin Le Grand case SVGTokenViewBox: 144ddde725dSArmin Le Grand { 145ddde725dSArmin Le Grand const basegfx::B2DRange aRange(readViewBox(aContent, *this)); 146ddde725dSArmin Le Grand 147ddde725dSArmin Le Grand if(!aRange.isEmpty()) 148ddde725dSArmin Le Grand { 149ddde725dSArmin Le Grand setViewBox(&aRange); 150ddde725dSArmin Le Grand } 151ddde725dSArmin Le Grand break; 152ddde725dSArmin Le Grand } 153ddde725dSArmin Le Grand case SVGTokenPreserveAspectRatio: 154ddde725dSArmin Le Grand { 155ddde725dSArmin Le Grand setSvgAspectRatio(readSvgAspectRatio(aContent)); 156ddde725dSArmin Le Grand break; 157ddde725dSArmin Le Grand } 158ddde725dSArmin Le Grand case SVGTokenX: 159ddde725dSArmin Le Grand { 160ddde725dSArmin Le Grand SvgNumber aNum; 161ddde725dSArmin Le Grand 162ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 163ddde725dSArmin Le Grand { 164ddde725dSArmin Le Grand setX(aNum); 165ddde725dSArmin Le Grand } 166ddde725dSArmin Le Grand break; 167ddde725dSArmin Le Grand } 168ddde725dSArmin Le Grand case SVGTokenY: 169ddde725dSArmin Le Grand { 170ddde725dSArmin Le Grand SvgNumber aNum; 171ddde725dSArmin Le Grand 172ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 173ddde725dSArmin Le Grand { 174ddde725dSArmin Le Grand setY(aNum); 175ddde725dSArmin Le Grand } 176ddde725dSArmin Le Grand break; 177ddde725dSArmin Le Grand } 178ddde725dSArmin Le Grand case SVGTokenWidth: 179ddde725dSArmin Le Grand { 180ddde725dSArmin Le Grand SvgNumber aNum; 181ddde725dSArmin Le Grand 182ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 183ddde725dSArmin Le Grand { 184ddde725dSArmin Le Grand if(aNum.isPositive()) 185ddde725dSArmin Le Grand { 186ddde725dSArmin Le Grand setWidth(aNum); 187ddde725dSArmin Le Grand } 188ddde725dSArmin Le Grand } 189ddde725dSArmin Le Grand break; 190ddde725dSArmin Le Grand } 191ddde725dSArmin Le Grand case SVGTokenHeight: 192ddde725dSArmin Le Grand { 193ddde725dSArmin Le Grand SvgNumber aNum; 194ddde725dSArmin Le Grand 195ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 196ddde725dSArmin Le Grand { 197ddde725dSArmin Le Grand if(aNum.isPositive()) 198ddde725dSArmin Le Grand { 199ddde725dSArmin Le Grand setHeight(aNum); 200ddde725dSArmin Le Grand } 201ddde725dSArmin Le Grand } 202ddde725dSArmin Le Grand break; 203ddde725dSArmin Le Grand } 204ddde725dSArmin Le Grand case SVGTokenVersion: 205ddde725dSArmin Le Grand { 206ddde725dSArmin Le Grand SvgNumber aNum; 207ddde725dSArmin Le Grand 208ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 209ddde725dSArmin Le Grand { 210ddde725dSArmin Le Grand setVersion(aNum); 211ddde725dSArmin Le Grand } 212ddde725dSArmin Le Grand break; 213e2bf1e9dSArmin Le Grand } 214e2bf1e9dSArmin Le Grand default: 215e2bf1e9dSArmin Le Grand { 216e2bf1e9dSArmin Le Grand break; 217ddde725dSArmin Le Grand } 218ddde725dSArmin Le Grand } 219ddde725dSArmin Le Grand } 220ddde725dSArmin Le Grand seekReferenceWidth(double & fWidth,bool & bHasFound) const2212169cc62SArmin Le Grand void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const 2222169cc62SArmin Le Grand { 2232169cc62SArmin Le Grand if (!getParent() || bHasFound) 2242169cc62SArmin Le Grand { 2252169cc62SArmin Le Grand return; 2262169cc62SArmin Le Grand } 2272169cc62SArmin Le Grand const SvgSvgNode* pParentSvgSvgNode = 0; 2282169cc62SArmin Le Grand // enclosing svg might have relative width, need to cumulate them till they are 2292169cc62SArmin Le Grand // resolved somewhere up in the node tree 2302169cc62SArmin Le Grand double fPercentage(1.0); 2312169cc62SArmin Le Grand for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) 2322169cc62SArmin Le Grand { 2332169cc62SArmin Le Grand // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition 2342169cc62SArmin Le Grand pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); 2352169cc62SArmin Le Grand if (pParentSvgSvgNode) 2362169cc62SArmin Le Grand { 2372169cc62SArmin Le Grand if (pParentSvgSvgNode->getViewBox()) 2382169cc62SArmin Le Grand { 2392169cc62SArmin Le Grand // viewbox values are already in 'user unit'. 2402169cc62SArmin Le Grand fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage; 2412169cc62SArmin Le Grand bHasFound = true; 2422169cc62SArmin Le Grand } 2432169cc62SArmin Le Grand else 2442169cc62SArmin Le Grand { 2452169cc62SArmin Le Grand // take absolute value or cummulate percentage 2462169cc62SArmin Le Grand if (pParentSvgSvgNode->getWidth().isSet()) 2472169cc62SArmin Le Grand { 2482169cc62SArmin Le Grand if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit()) 2492169cc62SArmin Le Grand { 2502169cc62SArmin Le Grand fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01; 2512169cc62SArmin Le Grand } 2522169cc62SArmin Le Grand else 2532169cc62SArmin Le Grand { 2542169cc62SArmin Le Grand fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; 2552169cc62SArmin Le Grand bHasFound = true; 2562169cc62SArmin Le Grand } 2572169cc62SArmin Le Grand } // not set => width=100% => factor 1, no need for else 2582169cc62SArmin Le Grand } 2592169cc62SArmin Le Grand } 2602169cc62SArmin Le Grand } 2612169cc62SArmin Le Grand } 2622169cc62SArmin Le Grand seekReferenceHeight(double & fHeight,bool & bHasFound) const2632169cc62SArmin Le Grand void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const 2642169cc62SArmin Le Grand { 2652169cc62SArmin Le Grand if (!getParent() || bHasFound) 2662169cc62SArmin Le Grand { 2672169cc62SArmin Le Grand return; 2682169cc62SArmin Le Grand } 2692169cc62SArmin Le Grand const SvgSvgNode* pParentSvgSvgNode = 0; 2702169cc62SArmin Le Grand // enclosing svg might have relative width and height, need to cumulate them till they are 2712169cc62SArmin Le Grand // resolved somewhere up in the node tree 2722169cc62SArmin Le Grand double fPercentage(1.0); 2732169cc62SArmin Le Grand for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) 2742169cc62SArmin Le Grand { 2752169cc62SArmin Le Grand // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition 2762169cc62SArmin Le Grand pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); 2772169cc62SArmin Le Grand if (pParentSvgSvgNode) 2782169cc62SArmin Le Grand { 2792169cc62SArmin Le Grand if (pParentSvgSvgNode->getViewBox()) 2802169cc62SArmin Le Grand { 2812169cc62SArmin Le Grand // viewbox values are already in 'user unit'. 2822169cc62SArmin Le Grand fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage; 2832169cc62SArmin Le Grand bHasFound = true; 2842169cc62SArmin Le Grand } 2852169cc62SArmin Le Grand else 2862169cc62SArmin Le Grand { 2872169cc62SArmin Le Grand // take absolute value or cummulate percentage 2882169cc62SArmin Le Grand if (pParentSvgSvgNode->getHeight().isSet()) 2892169cc62SArmin Le Grand { 2902169cc62SArmin Le Grand if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit()) 2912169cc62SArmin Le Grand { 2922169cc62SArmin Le Grand fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01; 2932169cc62SArmin Le Grand } 2942169cc62SArmin Le Grand else 2952169cc62SArmin Le Grand { 2962169cc62SArmin Le Grand fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; 2972169cc62SArmin Le Grand bHasFound = true; 2982169cc62SArmin Le Grand } 2992169cc62SArmin Le Grand } // not set => height=100% => factor 1, no need for else 3002169cc62SArmin Le Grand } 3012169cc62SArmin Le Grand } 3022169cc62SArmin Le Grand } 3032169cc62SArmin Le Grand } 3042169cc62SArmin Le Grand 3052169cc62SArmin Le Grand // ToDo: Consider attribute overflow in method decomposeSvgNode decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence & rTarget,bool bReferenced) const306ddde725dSArmin Le Grand void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 307ddde725dSArmin Le Grand { 308ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence aSequence; 309ddde725dSArmin Le Grand 3104374d266SArmin Le Grand // #125258# check now if we need to init some style settings locally. Do not do this 3114374d266SArmin Le Grand // in the constructor, there is not yet informatikon e.g. about existing CssStyles. 3124374d266SArmin Le Grand // Here all nodes are read and interpreted 3134374d266SArmin Le Grand const_cast< SvgSvgNode* >(this)->initializeStyleAttributes(); 3144374d266SArmin Le Grand 315ddde725dSArmin Le Grand // decompose childs 316ddde725dSArmin Le Grand SvgNode::decomposeSvgNode(aSequence, bReferenced); 317ddde725dSArmin Le Grand 318ddde725dSArmin Le Grand if(aSequence.hasElements()) 319ddde725dSArmin Le Grand { 320ddde725dSArmin Le Grand if(getParent()) 321ddde725dSArmin Le Grand { 3222169cc62SArmin Le Grand // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec). 323bca0eb5dSArmin Le Grand // If it is relative, the question is to what. The previous implementatin assumed relative to the 324bca0eb5dSArmin Le Grand // local ViewBox which is implied by (4.2 Basic data types): 325bca0eb5dSArmin Le Grand // 326bca0eb5dSArmin Le Grand // "Note that the non-property <length> definition also allows a percentage unit identifier. 327bca0eb5dSArmin Le Grand // The meaning of a percentage length value depends on the attribute for which the percentage 328bca0eb5dSArmin Le Grand // length value has been specified. Two common cases are: (a) when a percentage length value 329bca0eb5dSArmin Le Grand // represents a percentage of the viewport width or height (refer to the section that discusses 330bca0eb5dSArmin Le Grand // units in general), and (b) when a percentage length value represents a percentage of the 331bca0eb5dSArmin Le Grand // bounding box width or height on a given object (refer to the section that describes object 332bca0eb5dSArmin Le Grand // bounding box units)." 3332169cc62SArmin Le Grand 3342169cc62SArmin Le Grand // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport 3352169cc62SArmin Le Grand // of the parent, and so does the new implementation. 3362169cc62SArmin Le Grand 3372169cc62SArmin Le Grand // Extract known viewport data 3382169cc62SArmin Le Grand // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values 3392169cc62SArmin Le Grand 3402169cc62SArmin Le Grand // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 3412169cc62SArmin Le Grand // value 0.0 here is only to initialize variable 3422169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 3432169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 3442169cc62SArmin Le Grand 3452169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 3462169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 3472169cc62SArmin Le Grand 3482169cc62SArmin Le Grand // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 3492169cc62SArmin Le Grand bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); 3502169cc62SArmin Le Grand double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); 3512169cc62SArmin Le Grand 3522169cc62SArmin Le Grand bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); 3532169cc62SArmin Le Grand double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); 3542169cc62SArmin Le Grand 3552169cc62SArmin Le Grand if ( !bXIsAbsolute || !bWidthIsAbsolute) 356bca0eb5dSArmin Le Grand { 3572169cc62SArmin Le Grand // get width of enclosing svg and resolve percentage in x and width; 3582169cc62SArmin Le Grand double fWReference(0.0); 3592169cc62SArmin Le Grand bool bHasFoundWidth(false); 3602169cc62SArmin Le Grand seekReferenceWidth(fWReference, bHasFoundWidth); 3612169cc62SArmin Le Grand if (!bHasFoundWidth) 362bca0eb5dSArmin Le Grand { 3632169cc62SArmin Le Grand // Even outermost svg has not all information to resolve relative values, 3642169cc62SArmin Le Grand // I use content itself as fallback to set missing values for viewport 3652169cc62SArmin Le Grand // Any better idea for such ill structures svg documents? 3662169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 3672169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 3682169cc62SArmin Le Grand aSequence, 3692169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 3702169cc62SArmin Le Grand fWReference = aChildRange.getWidth(); 371bca0eb5dSArmin Le Grand } 3722169cc62SArmin Le Grand // referenced values are already in 'user unit' 3732169cc62SArmin Le Grand if (!bXIsAbsolute) 374bca0eb5dSArmin Le Grand { 3752169cc62SArmin Le Grand fX = getX().getNumber() * 0.01 * fWReference; 3762169cc62SArmin Le Grand } 3772169cc62SArmin Le Grand if (!bWidthIsAbsolute) 3782169cc62SArmin Le Grand { 3792169cc62SArmin Le Grand fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; 380bca0eb5dSArmin Le Grand } 381bca0eb5dSArmin Le Grand } 382bca0eb5dSArmin Le Grand 3832169cc62SArmin Le Grand if ( !bYIsAbsolute || !bHeightIsAbsolute) 384bca0eb5dSArmin Le Grand { 3852169cc62SArmin Le Grand // get height of enclosing svg and resolve percentage in y and height 3862169cc62SArmin Le Grand double fHReference(0.0); 3872169cc62SArmin Le Grand bool bHasFoundHeight(false); 3882169cc62SArmin Le Grand seekReferenceHeight(fHReference, bHasFoundHeight); 3892169cc62SArmin Le Grand if (!bHasFoundHeight) 3902169cc62SArmin Le Grand { 3912169cc62SArmin Le Grand // Even outermost svg has not all information to resolve relative values, 3922169cc62SArmin Le Grand // I use content itself as fallback to set missing values for viewport 3932169cc62SArmin Le Grand // Any better idea for such ill structures svg documents? 3942169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 3952169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 3962169cc62SArmin Le Grand aSequence, 3972169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 3982169cc62SArmin Le Grand fHReference = aChildRange.getHeight(); 3992169cc62SArmin Le Grand } 400bca0eb5dSArmin Le Grand 4012169cc62SArmin Le Grand // referenced values are already in 'user unit' 4022169cc62SArmin Le Grand if (!bYIsAbsolute) 403bca0eb5dSArmin Le Grand { 4042169cc62SArmin Le Grand fY = getY().getNumber() * 0.01 * fHReference; 4052169cc62SArmin Le Grand } 4062169cc62SArmin Le Grand if (!bHeightIsAbsolute) 4072169cc62SArmin Le Grand { 4082169cc62SArmin Le Grand fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; 409bca0eb5dSArmin Le Grand } 410bca0eb5dSArmin Le Grand } 411bca0eb5dSArmin Le Grand 412ddde725dSArmin Le Grand if(getViewBox()) 413ddde725dSArmin Le Grand { 4142169cc62SArmin Le Grand // SVG 1.1 defines in section 7.7 that a negative value for width or height 4152169cc62SArmin Le Grand // in viewBox is an error and that 0.0 disables rendering 4162169cc62SArmin Le Grand if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0)) 417ddde725dSArmin Le Grand { 4182169cc62SArmin Le Grand // create target range homing x,y, width and height as calculated above 419ddde725dSArmin Le Grand const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH); 420ddde725dSArmin Le Grand 421ddde725dSArmin Le Grand if(aTarget.equal(*getViewBox())) 422ddde725dSArmin Le Grand { 423ddde725dSArmin Le Grand // no mapping needed, append 424ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 425ddde725dSArmin Le Grand } 426ddde725dSArmin Le Grand else 427ddde725dSArmin Le Grand { 428ddde725dSArmin Le Grand // create mapping 4292169cc62SArmin Le Grand // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, 4302169cc62SArmin Le Grand // then the effect is as if a value of 'xMidYMid meet' were specified. 4312169cc62SArmin Le Grand SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); 4322169cc62SArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; 4332169cc62SArmin Le Grand 4342169cc62SArmin Le Grand // let mapping be created from SvgAspectRatio 4352169cc62SArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform( 4362169cc62SArmin Le Grand rRatio.createMapping(aTarget, *getViewBox())); 4372169cc62SArmin Le Grand 4382169cc62SArmin Le Grand // prepare embedding in transformation 4392169cc62SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 4402169cc62SArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 4412169cc62SArmin Le Grand aEmbeddingTransform, 4422169cc62SArmin Le Grand aSequence)); 443ddde725dSArmin Le Grand 4442169cc62SArmin Le Grand if(rRatio.isMeetOrSlice()) 445ddde725dSArmin Le Grand { 4462169cc62SArmin Le Grand // embed in transformation 4472169cc62SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); 448ddde725dSArmin Le Grand } 449ddde725dSArmin Le Grand else 450ddde725dSArmin Le Grand { 4512169cc62SArmin Le Grand // need to embed in MaskPrimitive2D, too 4522169cc62SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 4532169cc62SArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 4542169cc62SArmin Le Grand basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), 4552169cc62SArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); 456ddde725dSArmin Le Grand 4572169cc62SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 458ddde725dSArmin Le Grand } 459ddde725dSArmin Le Grand } 460ddde725dSArmin Le Grand } 461ddde725dSArmin Le Grand } 4622169cc62SArmin Le Grand else // no viewBox attribute 463ddde725dSArmin Le Grand { 464ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 465ddde725dSArmin Le Grand if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) 466ddde725dSArmin Le Grand { 467ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) 468ddde725dSArmin Le Grand { 469ddde725dSArmin Le Grand // embed in transform 470ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 471ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 472ddde725dSArmin Le Grand basegfx::tools::createTranslateB2DHomMatrix(fX, fY), 473ddde725dSArmin Le Grand aSequence)); 474ddde725dSArmin Le Grand 475ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 476ddde725dSArmin Le Grand } 477ddde725dSArmin Le Grand 478ddde725dSArmin Le Grand // embed in MaskPrimitive2D to clip 479ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 480ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 481ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 482ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 483ddde725dSArmin Le Grand basegfx::B2DRange(fX, fY, fX + fW, fY + fH))), 484ddde725dSArmin Le Grand aSequence)); 485ddde725dSArmin Le Grand 486ddde725dSArmin Le Grand // append 487ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 488ddde725dSArmin Le Grand } 489ddde725dSArmin Le Grand } 490ddde725dSArmin Le Grand } 4912169cc62SArmin Le Grand else // Outermost SVG element 492ddde725dSArmin Le Grand { 4932169cc62SArmin Le Grand double fW = 0.0; // effective value depends on viewBox 4942169cc62SArmin Le Grand double fH = 0.0; 495ddde725dSArmin Le Grand 496ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 4972169cc62SArmin Le Grand // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive' 4982169cc62SArmin Le Grand const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0)); 4992169cc62SArmin Le Grand const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0)); 5002169cc62SArmin Le Grand if(!bWidthInvalid && !bHeightInvalid) 501ddde725dSArmin Le Grand { 5022169cc62SArmin Le Grand basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox 503ddde725dSArmin Le Grand if(getViewBox()) 504ddde725dSArmin Le Grand { 5052169cc62SArmin Le Grand // SVG 1.1 defines in section 7.7 that a negative value for width or height 5062169cc62SArmin Le Grand // in viewBox is an error and that 0.0 disables rendering 5072169cc62SArmin Le Grand const double fViewBoxWidth = getViewBox()->getWidth(); 5082169cc62SArmin Le Grand const double fViewBoxHeight = getViewBox()->getHeight(); 5092169cc62SArmin Le Grand if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0)) 510ddde725dSArmin Le Grand { 5112169cc62SArmin Le Grand // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height 5122169cc62SArmin Le Grand // or if one or both of them is relative by the width and height of the viewBox 5132169cc62SArmin Le Grand // see SVG 1.1 section 7.12 5142169cc62SArmin Le Grand const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 5152169cc62SArmin Le Grand const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 5162169cc62SArmin Le Grand if(bWidthIsAbsolute && bHeightIsAbsolute) 517ddde725dSArmin Le Grand { 5182169cc62SArmin Le Grand fW =getWidth().solveNonPercentage(*this); 5192169cc62SArmin Le Grand fH =getHeight().solveNonPercentage(*this); 5202169cc62SArmin Le Grand } 5212169cc62SArmin Le Grand else if (bWidthIsAbsolute) 5222169cc62SArmin Le Grand { 5232169cc62SArmin Le Grand fW = getWidth().solveNonPercentage(*this); 5242169cc62SArmin Le Grand fH = fW * fViewBoxWidth / fViewBoxHeight ; 5252169cc62SArmin Le Grand } 5262169cc62SArmin Le Grand else if (bHeightIsAbsolute) 5272169cc62SArmin Le Grand { 5282169cc62SArmin Le Grand fH = getHeight().solveNonPercentage(*this); 5292169cc62SArmin Le Grand fW = fH * fViewBoxWidth / fViewBoxHeight ; 530ddde725dSArmin Le Grand } 531ddde725dSArmin Le Grand else 532ddde725dSArmin Le Grand { 5332169cc62SArmin Le Grand fW = fViewBoxWidth; 5342169cc62SArmin Le Grand fH = fViewBoxHeight; 535ddde725dSArmin Le Grand } 5362169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 5372169cc62SArmin Le Grand aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); 5382169cc62SArmin Le Grand 5392169cc62SArmin Le Grand // create mapping 5402169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, 5412169cc62SArmin Le Grand // then the effect is as if a value of 'xMidYMid meet' were specified. 5422169cc62SArmin Le Grand SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); 5432169cc62SArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; 5442169cc62SArmin Le Grand 5452169cc62SArmin Le Grand basegfx::B2DHomMatrix aViewBoxMapping; 5462169cc62SArmin Le Grand aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); 5472169cc62SArmin Le Grand // no need to check ratio here for slice, the outermost Svg will 5482169cc62SArmin Le Grand // be clipped anyways (see below) 549ddde725dSArmin Le Grand 550ddde725dSArmin Le Grand // scale content to viewBox definitions 551ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 552ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 553ddde725dSArmin Le Grand aViewBoxMapping, 554ddde725dSArmin Le Grand aSequence)); 555ddde725dSArmin Le Grand 556ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 557ddde725dSArmin Le Grand } 558ddde725dSArmin Le Grand } 5592169cc62SArmin Le Grand else // no viewbox 5602169cc62SArmin Le Grand { 5612169cc62SArmin Le Grand // There exists no parent to resolve relative width or height. 5622169cc62SArmin Le Grand // Use child size as fallback. 5632169cc62SArmin Le Grand const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 5642169cc62SArmin Le Grand const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 5652169cc62SArmin Le Grand if (bWidthIsAbsolute && bHeightIsAbsolute) 5662169cc62SArmin Le Grand { 5672169cc62SArmin Le Grand fW =getWidth().solveNonPercentage(*this); 5682169cc62SArmin Le Grand fH =getHeight().solveNonPercentage(*this); 5692169cc62SArmin Le Grand 5702169cc62SArmin Le Grand } 5712169cc62SArmin Le Grand else 5722169cc62SArmin Le Grand { 5732169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 5742169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 5752169cc62SArmin Le Grand aSequence, 5762169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 5772169cc62SArmin Le Grand const double fChildWidth(aChildRange.getWidth()); 5782169cc62SArmin Le Grand const double fChildHeight(aChildRange.getHeight()); 5792169cc62SArmin Le Grand fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth; 5802169cc62SArmin Le Grand fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight; 5812169cc62SArmin Le Grand } 5822169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 5832169cc62SArmin Le Grand aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); 5842169cc62SArmin Le Grand } 585ddde725dSArmin Le Grand 586ddde725dSArmin Le Grand // to be completely correct in Svg sense it is necessary to clip 587ddde725dSArmin Le Grand // the whole content to the given canvas. I choose here to do this 588ddde725dSArmin Le Grand // initially despite I found various examples of Svg files out there 589ddde725dSArmin Le Grand // which have no correct values for this clipping. It's correct 590ddde725dSArmin Le Grand // due to the Svg spec. 591ddde725dSArmin Le Grand bool bDoCorrectCanvasClipping(true); 592ddde725dSArmin Le Grand 593ddde725dSArmin Le Grand if(bDoCorrectCanvasClipping) 594ddde725dSArmin Le Grand { 595ddde725dSArmin Le Grand // different from Svg we have the possibility with primitives to get 59641923119SArmin Le Grand // a correct bounding box for the geometry. Get it for evtl. taking action 597ddde725dSArmin Le Grand const basegfx::B2DRange aContentRange( 598ddde725dSArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 599ddde725dSArmin Le Grand aSequence, 600ddde725dSArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 601ddde725dSArmin Le Grand 60241923119SArmin Le Grand if(aSvgCanvasRange.isInside(aContentRange)) 603ddde725dSArmin Le Grand { 60441923119SArmin Le Grand // no clip needed, but an invisible HiddenGeometryPrimitive2D 60541923119SArmin Le Grand // to allow getting the full Svg range using the primitive mechanisms. 60641923119SArmin Le Grand // This is needed since e.g. an SdrObject using this as graphic will 60741923119SArmin Le Grand // create a mapping transformation to exactly map the content to it's 60841923119SArmin Le Grand // real life size 60941923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xLine( 61041923119SArmin Le Grand new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( 61141923119SArmin Le Grand basegfx::tools::createPolygonFromRect( 61241923119SArmin Le Grand aSvgCanvasRange), 61341923119SArmin Le Grand basegfx::BColor(0.0, 0.0, 0.0))); 61441923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xHidden( 61541923119SArmin Le Grand new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( 61641923119SArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1))); 61741923119SArmin Le Grand 61841923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden); 61941923119SArmin Le Grand } 62041923119SArmin Le Grand else if(aSvgCanvasRange.overlaps(aContentRange)) 62141923119SArmin Le Grand { 62241923119SArmin Le Grand // Clip is necessary. This will make Svg images evtl. smaller 62341923119SArmin Le Grand // than wanted from Svg (the free space which may be around it is 62486e1cf34SPedro Giffuni // conform to the Svg spec), but avoids an expensive and unnecessary 62541923119SArmin Le Grand // clip. Keep the full Svg range here to get the correct mappings 62641923119SArmin Le Grand // to objects using this. Optimizations can be done in the processors 627ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 628ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 629ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 630ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 631ddde725dSArmin Le Grand aSvgCanvasRange)), 632ddde725dSArmin Le Grand aSequence)); 633ddde725dSArmin Le Grand 634ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); 635ddde725dSArmin Le Grand } 63641923119SArmin Le Grand else 63741923119SArmin Le Grand { 63841923119SArmin Le Grand // not inside, no overlap. Empty Svg 63941923119SArmin Le Grand aSequence.realloc(0); 64041923119SArmin Le Grand } 641ddde725dSArmin Le Grand } 642ddde725dSArmin Le Grand 64341923119SArmin Le Grand if(aSequence.hasElements()) 644ddde725dSArmin Le Grand { 645ddde725dSArmin Le Grand // embed in transform primitive to scale to 1/100th mm 6462169cc62SArmin Le Grand // where 1 inch == 25.4 mm to get from Svg coordinates (px) to 6472169cc62SArmin Le Grand // drawinglayer coordinates 6482169cc62SArmin Le Grand const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH); 649ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aTransform( 650ddde725dSArmin Le Grand basegfx::tools::createScaleB2DHomMatrix( 651ddde725dSArmin Le Grand fScaleTo100thmm, 652ddde725dSArmin Le Grand fScaleTo100thmm)); 653ddde725dSArmin Le Grand 654ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 655ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 656ddde725dSArmin Le Grand aTransform, 657ddde725dSArmin Le Grand aSequence)); 658ddde725dSArmin Le Grand 659ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 660ddde725dSArmin Le Grand 66141923119SArmin Le Grand // append to result 66241923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 66341923119SArmin Le Grand } 664ddde725dSArmin Le Grand } 665ddde725dSArmin Le Grand } 666ddde725dSArmin Le Grand } 667ddde725dSArmin Le Grand } 668ddde725dSArmin Le Grand getCurrentViewPort() const669e92bb418SOliver-Rainer Wittmann const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const 670ddde725dSArmin Le Grand { 671ddde725dSArmin Le Grand if(getViewBox()) 672ddde725dSArmin Le Grand { 673e92bb418SOliver-Rainer Wittmann return *(getViewBox()); 674ddde725dSArmin Le Grand } 6752169cc62SArmin Le Grand else // viewport should be given by x, y, width, and height 676ddde725dSArmin Le Grand { 6772169cc62SArmin Le Grand // Extract known viewport data 6782169cc62SArmin Le Grand // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values 6792169cc62SArmin Le Grand if (getParent()) 6802169cc62SArmin Le Grand { 6812169cc62SArmin Le Grand // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 6822169cc62SArmin Le Grand // value 0.0 here is only to initialize variable 6832169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 6842169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 6852169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 6862169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 6872169cc62SArmin Le Grand 6882169cc62SArmin Le Grand // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 6892169cc62SArmin Le Grand bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); 6902169cc62SArmin Le Grand double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); 6912169cc62SArmin Le Grand 6922169cc62SArmin Le Grand bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); 6932169cc62SArmin Le Grand double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); 6942169cc62SArmin Le Grand 6952169cc62SArmin Le Grand if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) 6962169cc62SArmin Le Grand { 697e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(fX, fY, fX+fW, fY+fH); 6982169cc62SArmin Le Grand } 6992169cc62SArmin Le Grand else // try to resolve relative values 7002169cc62SArmin Le Grand { 7012169cc62SArmin Le Grand if (!bXIsAbsolute || !bWidthIsAbsolute) 7022169cc62SArmin Le Grand { 7032169cc62SArmin Le Grand // get width of enclosing svg and resolve percentage in x and width 7042169cc62SArmin Le Grand double fWReference(0.0); 7052169cc62SArmin Le Grand bool bHasFoundWidth(false); 7062169cc62SArmin Le Grand seekReferenceWidth(fWReference, bHasFoundWidth); 7072169cc62SArmin Le Grand // referenced values are already in 'user unit' 7082169cc62SArmin Le Grand if (!bXIsAbsolute && bHasFoundWidth) 7092169cc62SArmin Le Grand { 7102169cc62SArmin Le Grand fX = getX().getNumber() * 0.01 * fWReference; 7112169cc62SArmin Le Grand bXIsAbsolute = true; 7122169cc62SArmin Le Grand } 7132169cc62SArmin Le Grand if (!bWidthIsAbsolute && bHasFoundWidth) 7142169cc62SArmin Le Grand { 7152169cc62SArmin Le Grand fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; 7162169cc62SArmin Le Grand bWidthIsAbsolute = true; 7172169cc62SArmin Le Grand } 7182169cc62SArmin Le Grand } 7192169cc62SArmin Le Grand if (!bYIsAbsolute || !bHeightIsAbsolute) 7202169cc62SArmin Le Grand { 7212169cc62SArmin Le Grand // get height of enclosing svg and resolve percentage in y and height 7222169cc62SArmin Le Grand double fHReference(0.0); 7232169cc62SArmin Le Grand bool bHasFoundHeight(false); 7242169cc62SArmin Le Grand seekReferenceHeight(fHReference, bHasFoundHeight); 7252169cc62SArmin Le Grand // referenced values are already in 'user unit' 7262169cc62SArmin Le Grand if (!bYIsAbsolute && bHasFoundHeight) 7272169cc62SArmin Le Grand { 7282169cc62SArmin Le Grand fY = getY().getNumber() * 0.01 * fHReference; 7292169cc62SArmin Le Grand bYIsAbsolute = true; 7302169cc62SArmin Le Grand } 7312169cc62SArmin Le Grand if (!bHeightIsAbsolute && bHasFoundHeight) 7322169cc62SArmin Le Grand { 7332169cc62SArmin Le Grand fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; 7342169cc62SArmin Le Grand bHeightIsAbsolute = true; 7352169cc62SArmin Le Grand } 7362169cc62SArmin Le Grand } 7372169cc62SArmin Le Grand 7382169cc62SArmin Le Grand if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) 7392169cc62SArmin Le Grand { 740e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(fX, fY, fX+fW, fY+fH); 7412169cc62SArmin Le Grand } 7422169cc62SArmin Le Grand else // relative values could not be resolved, there exists no fallback 7432169cc62SArmin Le Grand { 7442169cc62SArmin Le Grand return SvgNode::getCurrentViewPort(); 7452169cc62SArmin Le Grand } 7462169cc62SArmin Le Grand } 7472169cc62SArmin Le Grand } 7482169cc62SArmin Le Grand else //outermost svg 7492169cc62SArmin Le Grand { 7502169cc62SArmin Le Grand // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2 7512169cc62SArmin Le Grand // But here it cannot be resolved and no fallback exists. 7522169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 7532169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 7542169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 7552169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 7562169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 7572169cc62SArmin Le Grand if (bWidthIsAbsolute && bHeightIsAbsolute) 7582169cc62SArmin Le Grand { 759e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(0.0, 0.0, fW, fH); 7602169cc62SArmin Le Grand } 7612169cc62SArmin Le Grand else // no fallback exists 7622169cc62SArmin Le Grand { 7632169cc62SArmin Le Grand return SvgNode::getCurrentViewPort(); 7642169cc62SArmin Le Grand } 7652169cc62SArmin Le Grand } 7662169cc62SArmin Le Grand // ToDo: Is it possible to decompose and use the bounding box of the childs, if even the 7672169cc62SArmin Le Grand // outermost svg has no information to resolve percentage? Is it worth, how expensive is it? 7682169cc62SArmin Le Grand 769ddde725dSArmin Le Grand } 770ddde725dSArmin Le Grand } 771ddde725dSArmin Le Grand 772ddde725dSArmin Le Grand } // end of namespace svgreader 773ddde725dSArmin Le Grand } // end of namespace svgio 774ddde725dSArmin Le Grand 775ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 776ddde725dSArmin Le Grand // eof 777