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 { 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(), 52*4374d266SArmin Le Grand maVersion(), 53*4374d266SArmin Le Grand mbStyleAttributesInitialized(false) // #125258# 54ddde725dSArmin Le Grand { 55*4374d266SArmin Le Grand } 56*4374d266SArmin Le Grand 57*4374d266SArmin Le Grand // #125258# 58*4374d266SArmin Le Grand void SvgSvgNode::initializeStyleAttributes() 59*4374d266SArmin Le Grand { 60*4374d266SArmin Le Grand if(!mbStyleAttributesInitialized) 61ddde725dSArmin Le Grand { 62*4374d266SArmin Le Grand // #125258# determine if initial values need to be initialized with hard values 63*4374d266SArmin Le Grand // for the case that this is the outmost SVG statement and it has no parent 64*4374d266SArmin Le Grand // stale (CssStyle for svg may be defined) 65*4374d266SArmin Le Grand bool bSetInitialValues(true); 66*4374d266SArmin Le Grand 67*4374d266SArmin Le Grand if(getParent()) 68*4374d266SArmin Le Grand { 69*4374d266SArmin Le Grand // #125258# no initial values when it's a SVG element embedded in SVG 70*4374d266SArmin Le Grand bSetInitialValues = false; 71*4374d266SArmin Le Grand } 72*4374d266SArmin Le Grand 73*4374d266SArmin Le Grand if(bSetInitialValues) 74*4374d266SArmin Le Grand { 75*4374d266SArmin Le Grand const SvgStyleAttributes* pStyles = getSvgStyleAttributes(); 76*4374d266SArmin Le Grand 77*4374d266SArmin Le Grand if(pStyles && pStyles->getParentStyle()) 78*4374d266SArmin Le Grand { 79*4374d266SArmin Le Grand // #125258# no initial values when SVG has a parent style (probably CssStyle) 80*4374d266SArmin Le Grand bSetInitialValues = false; 81*4374d266SArmin Le Grand } 82*4374d266SArmin Le Grand } 83*4374d266SArmin Le Grand 84*4374d266SArmin Le Grand if(bSetInitialValues) 85*4374d266SArmin Le Grand { 86*4374d266SArmin Le Grand // #125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done, 87*4374d266SArmin Le Grand // just setting may revert an already set valid value) 88*4374d266SArmin Le Grand if(!maSvgStyleAttributes.isFillSet()) 89*4374d266SArmin Le Grand { 90*4374d266SArmin Le Grand // #125258# initial fill is black (see SVG1.1 spec) 91*4374d266SArmin Le Grand maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); 92*4374d266SArmin Le Grand } 93*4374d266SArmin Le Grand } 94*4374d266SArmin Le Grand 95*4374d266SArmin Le Grand mbStyleAttributesInitialized = true; 96ddde725dSArmin Le Grand } 97ddde725dSArmin Le Grand } 98ddde725dSArmin Le Grand 99ddde725dSArmin Le Grand SvgSvgNode::~SvgSvgNode() 100ddde725dSArmin Le Grand { 101ddde725dSArmin Le Grand if(mpViewBox) delete mpViewBox; 102ddde725dSArmin Le Grand } 103ddde725dSArmin Le Grand 104ddde725dSArmin Le Grand const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const 105ddde725dSArmin Le Grand { 106*4374d266SArmin Le Grand // #125258# svg node can vahe CssStyles, too, so check for it here 107*4374d266SArmin Le Grand static rtl::OUString aClassStr(rtl::OUString::createFromAscii("svg")); 108*4374d266SArmin Le Grand 109*4374d266SArmin Le Grand return checkForCssStyle(aClassStr, maSvgStyleAttributes); 110ddde725dSArmin Le Grand } 111ddde725dSArmin Le Grand 112ddde725dSArmin Le Grand void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) 113ddde725dSArmin Le Grand { 114ddde725dSArmin Le Grand // call parent 115ddde725dSArmin Le Grand SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); 116ddde725dSArmin Le Grand 117ddde725dSArmin Le Grand // read style attributes 118ddde725dSArmin Le Grand maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); 119ddde725dSArmin Le Grand 120ddde725dSArmin Le Grand // parse own 121ddde725dSArmin Le Grand switch(aSVGToken) 122ddde725dSArmin Le Grand { 123ddde725dSArmin Le Grand case SVGTokenStyle: 124ddde725dSArmin Le Grand { 125ddde725dSArmin Le Grand maSvgStyleAttributes.readStyle(aContent); 126ddde725dSArmin Le Grand break; 127ddde725dSArmin Le Grand } 128ddde725dSArmin Le Grand case SVGTokenViewBox: 129ddde725dSArmin Le Grand { 130ddde725dSArmin Le Grand const basegfx::B2DRange aRange(readViewBox(aContent, *this)); 131ddde725dSArmin Le Grand 132ddde725dSArmin Le Grand if(!aRange.isEmpty()) 133ddde725dSArmin Le Grand { 134ddde725dSArmin Le Grand setViewBox(&aRange); 135ddde725dSArmin Le Grand } 136ddde725dSArmin Le Grand break; 137ddde725dSArmin Le Grand } 138ddde725dSArmin Le Grand case SVGTokenPreserveAspectRatio: 139ddde725dSArmin Le Grand { 140ddde725dSArmin Le Grand setSvgAspectRatio(readSvgAspectRatio(aContent)); 141ddde725dSArmin Le Grand break; 142ddde725dSArmin Le Grand } 143ddde725dSArmin Le Grand case SVGTokenX: 144ddde725dSArmin Le Grand { 145ddde725dSArmin Le Grand SvgNumber aNum; 146ddde725dSArmin Le Grand 147ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 148ddde725dSArmin Le Grand { 149ddde725dSArmin Le Grand setX(aNum); 150ddde725dSArmin Le Grand } 151ddde725dSArmin Le Grand break; 152ddde725dSArmin Le Grand } 153ddde725dSArmin Le Grand case SVGTokenY: 154ddde725dSArmin Le Grand { 155ddde725dSArmin Le Grand SvgNumber aNum; 156ddde725dSArmin Le Grand 157ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 158ddde725dSArmin Le Grand { 159ddde725dSArmin Le Grand setY(aNum); 160ddde725dSArmin Le Grand } 161ddde725dSArmin Le Grand break; 162ddde725dSArmin Le Grand } 163ddde725dSArmin Le Grand case SVGTokenWidth: 164ddde725dSArmin Le Grand { 165ddde725dSArmin Le Grand SvgNumber aNum; 166ddde725dSArmin Le Grand 167ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 168ddde725dSArmin Le Grand { 169ddde725dSArmin Le Grand if(aNum.isPositive()) 170ddde725dSArmin Le Grand { 171ddde725dSArmin Le Grand setWidth(aNum); 172ddde725dSArmin Le Grand } 173ddde725dSArmin Le Grand } 174ddde725dSArmin Le Grand break; 175ddde725dSArmin Le Grand } 176ddde725dSArmin Le Grand case SVGTokenHeight: 177ddde725dSArmin Le Grand { 178ddde725dSArmin Le Grand SvgNumber aNum; 179ddde725dSArmin Le Grand 180ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 181ddde725dSArmin Le Grand { 182ddde725dSArmin Le Grand if(aNum.isPositive()) 183ddde725dSArmin Le Grand { 184ddde725dSArmin Le Grand setHeight(aNum); 185ddde725dSArmin Le Grand } 186ddde725dSArmin Le Grand } 187ddde725dSArmin Le Grand break; 188ddde725dSArmin Le Grand } 189ddde725dSArmin Le Grand case SVGTokenVersion: 190ddde725dSArmin Le Grand { 191ddde725dSArmin Le Grand SvgNumber aNum; 192ddde725dSArmin Le Grand 193ddde725dSArmin Le Grand if(readSingleNumber(aContent, aNum)) 194ddde725dSArmin Le Grand { 195ddde725dSArmin Le Grand setVersion(aNum); 196ddde725dSArmin Le Grand } 197ddde725dSArmin Le Grand break; 198e2bf1e9dSArmin Le Grand } 199e2bf1e9dSArmin Le Grand default: 200e2bf1e9dSArmin Le Grand { 201e2bf1e9dSArmin Le Grand break; 202ddde725dSArmin Le Grand } 203ddde725dSArmin Le Grand } 204ddde725dSArmin Le Grand } 205ddde725dSArmin Le Grand 2062169cc62SArmin Le Grand void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const 2072169cc62SArmin Le Grand { 2082169cc62SArmin Le Grand if (!getParent() || bHasFound) 2092169cc62SArmin Le Grand { 2102169cc62SArmin Le Grand return; 2112169cc62SArmin Le Grand } 2122169cc62SArmin Le Grand const SvgSvgNode* pParentSvgSvgNode = 0; 2132169cc62SArmin Le Grand // enclosing svg might have relative width, need to cumulate them till they are 2142169cc62SArmin Le Grand // resolved somewhere up in the node tree 2152169cc62SArmin Le Grand double fPercentage(1.0); 2162169cc62SArmin Le Grand for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) 2172169cc62SArmin Le Grand { 2182169cc62SArmin Le Grand // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition 2192169cc62SArmin Le Grand pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); 2202169cc62SArmin Le Grand if (pParentSvgSvgNode) 2212169cc62SArmin Le Grand { 2222169cc62SArmin Le Grand if (pParentSvgSvgNode->getViewBox()) 2232169cc62SArmin Le Grand { 2242169cc62SArmin Le Grand // viewbox values are already in 'user unit'. 2252169cc62SArmin Le Grand fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage; 2262169cc62SArmin Le Grand bHasFound = true; 2272169cc62SArmin Le Grand } 2282169cc62SArmin Le Grand else 2292169cc62SArmin Le Grand { 2302169cc62SArmin Le Grand // take absolute value or cummulate percentage 2312169cc62SArmin Le Grand if (pParentSvgSvgNode->getWidth().isSet()) 2322169cc62SArmin Le Grand { 2332169cc62SArmin Le Grand if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit()) 2342169cc62SArmin Le Grand { 2352169cc62SArmin Le Grand fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01; 2362169cc62SArmin Le Grand } 2372169cc62SArmin Le Grand else 2382169cc62SArmin Le Grand { 2392169cc62SArmin Le Grand fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; 2402169cc62SArmin Le Grand bHasFound = true; 2412169cc62SArmin Le Grand } 2422169cc62SArmin Le Grand } // not set => width=100% => factor 1, no need for else 2432169cc62SArmin Le Grand } 2442169cc62SArmin Le Grand } 2452169cc62SArmin Le Grand } 2462169cc62SArmin Le Grand } 2472169cc62SArmin Le Grand 2482169cc62SArmin Le Grand void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const 2492169cc62SArmin Le Grand { 2502169cc62SArmin Le Grand if (!getParent() || bHasFound) 2512169cc62SArmin Le Grand { 2522169cc62SArmin Le Grand return; 2532169cc62SArmin Le Grand } 2542169cc62SArmin Le Grand const SvgSvgNode* pParentSvgSvgNode = 0; 2552169cc62SArmin Le Grand // enclosing svg might have relative width and height, need to cumulate them till they are 2562169cc62SArmin Le Grand // resolved somewhere up in the node tree 2572169cc62SArmin Le Grand double fPercentage(1.0); 2582169cc62SArmin Le Grand for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) 2592169cc62SArmin Le Grand { 2602169cc62SArmin Le Grand // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition 2612169cc62SArmin Le Grand pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); 2622169cc62SArmin Le Grand if (pParentSvgSvgNode) 2632169cc62SArmin Le Grand { 2642169cc62SArmin Le Grand if (pParentSvgSvgNode->getViewBox()) 2652169cc62SArmin Le Grand { 2662169cc62SArmin Le Grand // viewbox values are already in 'user unit'. 2672169cc62SArmin Le Grand fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage; 2682169cc62SArmin Le Grand bHasFound = true; 2692169cc62SArmin Le Grand } 2702169cc62SArmin Le Grand else 2712169cc62SArmin Le Grand { 2722169cc62SArmin Le Grand // take absolute value or cummulate percentage 2732169cc62SArmin Le Grand if (pParentSvgSvgNode->getHeight().isSet()) 2742169cc62SArmin Le Grand { 2752169cc62SArmin Le Grand if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit()) 2762169cc62SArmin Le Grand { 2772169cc62SArmin Le Grand fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01; 2782169cc62SArmin Le Grand } 2792169cc62SArmin Le Grand else 2802169cc62SArmin Le Grand { 2812169cc62SArmin Le Grand fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; 2822169cc62SArmin Le Grand bHasFound = true; 2832169cc62SArmin Le Grand } 2842169cc62SArmin Le Grand } // not set => height=100% => factor 1, no need for else 2852169cc62SArmin Le Grand } 2862169cc62SArmin Le Grand } 2872169cc62SArmin Le Grand } 2882169cc62SArmin Le Grand } 2892169cc62SArmin Le Grand 2902169cc62SArmin Le Grand // ToDo: Consider attribute overflow in method decomposeSvgNode 291ddde725dSArmin Le Grand void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const 292ddde725dSArmin Le Grand { 293ddde725dSArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence aSequence; 294ddde725dSArmin Le Grand 295*4374d266SArmin Le Grand // #125258# check now if we need to init some style settings locally. Do not do this 296*4374d266SArmin Le Grand // in the constructor, there is not yet informatikon e.g. about existing CssStyles. 297*4374d266SArmin Le Grand // Here all nodes are read and interpreted 298*4374d266SArmin Le Grand const_cast< SvgSvgNode* >(this)->initializeStyleAttributes(); 299*4374d266SArmin Le Grand 300ddde725dSArmin Le Grand // decompose childs 301ddde725dSArmin Le Grand SvgNode::decomposeSvgNode(aSequence, bReferenced); 302ddde725dSArmin Le Grand 303ddde725dSArmin Le Grand if(aSequence.hasElements()) 304ddde725dSArmin Le Grand { 305ddde725dSArmin Le Grand if(getParent()) 306ddde725dSArmin Le Grand { 3072169cc62SArmin Le Grand // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec). 308bca0eb5dSArmin Le Grand // If it is relative, the question is to what. The previous implementatin assumed relative to the 309bca0eb5dSArmin Le Grand // local ViewBox which is implied by (4.2 Basic data types): 310bca0eb5dSArmin Le Grand // 311bca0eb5dSArmin Le Grand // "Note that the non-property <length> definition also allows a percentage unit identifier. 312bca0eb5dSArmin Le Grand // The meaning of a percentage length value depends on the attribute for which the percentage 313bca0eb5dSArmin Le Grand // length value has been specified. Two common cases are: (a) when a percentage length value 314bca0eb5dSArmin Le Grand // represents a percentage of the viewport width or height (refer to the section that discusses 315bca0eb5dSArmin Le Grand // units in general), and (b) when a percentage length value represents a percentage of the 316bca0eb5dSArmin Le Grand // bounding box width or height on a given object (refer to the section that describes object 317bca0eb5dSArmin Le Grand // bounding box units)." 3182169cc62SArmin Le Grand 3192169cc62SArmin Le Grand // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport 3202169cc62SArmin Le Grand // of the parent, and so does the new implementation. 3212169cc62SArmin Le Grand 3222169cc62SArmin Le Grand // Extract known viewport data 3232169cc62SArmin Le Grand // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values 3242169cc62SArmin Le Grand 3252169cc62SArmin Le Grand // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 3262169cc62SArmin Le Grand // value 0.0 here is only to initialize variable 3272169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 3282169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 3292169cc62SArmin Le Grand 3302169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 3312169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 3322169cc62SArmin Le Grand 3332169cc62SArmin Le Grand // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 3342169cc62SArmin Le Grand bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); 3352169cc62SArmin Le Grand double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); 3362169cc62SArmin Le Grand 3372169cc62SArmin Le Grand bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); 3382169cc62SArmin Le Grand double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); 3392169cc62SArmin Le Grand 3402169cc62SArmin Le Grand if ( !bXIsAbsolute || !bWidthIsAbsolute) 341bca0eb5dSArmin Le Grand { 3422169cc62SArmin Le Grand // get width of enclosing svg and resolve percentage in x and width; 3432169cc62SArmin Le Grand double fWReference(0.0); 3442169cc62SArmin Le Grand bool bHasFoundWidth(false); 3452169cc62SArmin Le Grand seekReferenceWidth(fWReference, bHasFoundWidth); 3462169cc62SArmin Le Grand if (!bHasFoundWidth) 347bca0eb5dSArmin Le Grand { 3482169cc62SArmin Le Grand // Even outermost svg has not all information to resolve relative values, 3492169cc62SArmin Le Grand // I use content itself as fallback to set missing values for viewport 3502169cc62SArmin Le Grand // Any better idea for such ill structures svg documents? 3512169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 3522169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 3532169cc62SArmin Le Grand aSequence, 3542169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 3552169cc62SArmin Le Grand fWReference = aChildRange.getWidth(); 356bca0eb5dSArmin Le Grand } 3572169cc62SArmin Le Grand // referenced values are already in 'user unit' 3582169cc62SArmin Le Grand if (!bXIsAbsolute) 359bca0eb5dSArmin Le Grand { 3602169cc62SArmin Le Grand fX = getX().getNumber() * 0.01 * fWReference; 3612169cc62SArmin Le Grand } 3622169cc62SArmin Le Grand if (!bWidthIsAbsolute) 3632169cc62SArmin Le Grand { 3642169cc62SArmin Le Grand fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; 365bca0eb5dSArmin Le Grand } 366bca0eb5dSArmin Le Grand } 367bca0eb5dSArmin Le Grand 3682169cc62SArmin Le Grand if ( !bYIsAbsolute || !bHeightIsAbsolute) 369bca0eb5dSArmin Le Grand { 3702169cc62SArmin Le Grand // get height of enclosing svg and resolve percentage in y and height 3712169cc62SArmin Le Grand double fHReference(0.0); 3722169cc62SArmin Le Grand bool bHasFoundHeight(false); 3732169cc62SArmin Le Grand seekReferenceHeight(fHReference, bHasFoundHeight); 3742169cc62SArmin Le Grand if (!bHasFoundHeight) 3752169cc62SArmin Le Grand { 3762169cc62SArmin Le Grand // Even outermost svg has not all information to resolve relative values, 3772169cc62SArmin Le Grand // I use content itself as fallback to set missing values for viewport 3782169cc62SArmin Le Grand // Any better idea for such ill structures svg documents? 3792169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 3802169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 3812169cc62SArmin Le Grand aSequence, 3822169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 3832169cc62SArmin Le Grand fHReference = aChildRange.getHeight(); 3842169cc62SArmin Le Grand } 385bca0eb5dSArmin Le Grand 3862169cc62SArmin Le Grand // referenced values are already in 'user unit' 3872169cc62SArmin Le Grand if (!bYIsAbsolute) 388bca0eb5dSArmin Le Grand { 3892169cc62SArmin Le Grand fY = getY().getNumber() * 0.01 * fHReference; 3902169cc62SArmin Le Grand } 3912169cc62SArmin Le Grand if (!bHeightIsAbsolute) 3922169cc62SArmin Le Grand { 3932169cc62SArmin Le Grand fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; 394bca0eb5dSArmin Le Grand } 395bca0eb5dSArmin Le Grand } 396bca0eb5dSArmin Le Grand 397ddde725dSArmin Le Grand if(getViewBox()) 398ddde725dSArmin Le Grand { 3992169cc62SArmin Le Grand // SVG 1.1 defines in section 7.7 that a negative value for width or height 4002169cc62SArmin Le Grand // in viewBox is an error and that 0.0 disables rendering 4012169cc62SArmin Le Grand if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0)) 402ddde725dSArmin Le Grand { 4032169cc62SArmin Le Grand // create target range homing x,y, width and height as calculated above 404ddde725dSArmin Le Grand const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH); 405ddde725dSArmin Le Grand 406ddde725dSArmin Le Grand if(aTarget.equal(*getViewBox())) 407ddde725dSArmin Le Grand { 408ddde725dSArmin Le Grand // no mapping needed, append 409ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 410ddde725dSArmin Le Grand } 411ddde725dSArmin Le Grand else 412ddde725dSArmin Le Grand { 413ddde725dSArmin Le Grand // create mapping 4142169cc62SArmin Le Grand // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, 4152169cc62SArmin Le Grand // then the effect is as if a value of 'xMidYMid meet' were specified. 4162169cc62SArmin Le Grand SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); 4172169cc62SArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; 4182169cc62SArmin Le Grand 4192169cc62SArmin Le Grand // let mapping be created from SvgAspectRatio 4202169cc62SArmin Le Grand const basegfx::B2DHomMatrix aEmbeddingTransform( 4212169cc62SArmin Le Grand rRatio.createMapping(aTarget, *getViewBox())); 4222169cc62SArmin Le Grand 4232169cc62SArmin Le Grand // prepare embedding in transformation 4242169cc62SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 4252169cc62SArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 4262169cc62SArmin Le Grand aEmbeddingTransform, 4272169cc62SArmin Le Grand aSequence)); 428ddde725dSArmin Le Grand 4292169cc62SArmin Le Grand if(rRatio.isMeetOrSlice()) 430ddde725dSArmin Le Grand { 4312169cc62SArmin Le Grand // embed in transformation 4322169cc62SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); 433ddde725dSArmin Le Grand } 434ddde725dSArmin Le Grand else 435ddde725dSArmin Le Grand { 4362169cc62SArmin Le Grand // need to embed in MaskPrimitive2D, too 4372169cc62SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 4382169cc62SArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 4392169cc62SArmin Le Grand basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), 4402169cc62SArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); 441ddde725dSArmin Le Grand 4422169cc62SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 443ddde725dSArmin Le Grand } 444ddde725dSArmin Le Grand } 445ddde725dSArmin Le Grand } 446ddde725dSArmin Le Grand } 4472169cc62SArmin Le Grand else // no viewBox attribute 448ddde725dSArmin Le Grand { 449ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 450ddde725dSArmin Le Grand if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) 451ddde725dSArmin Le Grand { 452ddde725dSArmin Le Grand if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) 453ddde725dSArmin Le Grand { 454ddde725dSArmin Le Grand // embed in transform 455ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xRef( 456ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 457ddde725dSArmin Le Grand basegfx::tools::createTranslateB2DHomMatrix(fX, fY), 458ddde725dSArmin Le Grand aSequence)); 459ddde725dSArmin Le Grand 460ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); 461ddde725dSArmin Le Grand } 462ddde725dSArmin Le Grand 463ddde725dSArmin Le Grand // embed in MaskPrimitive2D to clip 464ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 465ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 466ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 467ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 468ddde725dSArmin Le Grand basegfx::B2DRange(fX, fY, fX + fW, fY + fH))), 469ddde725dSArmin Le Grand aSequence)); 470ddde725dSArmin Le Grand 471ddde725dSArmin Le Grand // append 472ddde725dSArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); 473ddde725dSArmin Le Grand } 474ddde725dSArmin Le Grand } 475ddde725dSArmin Le Grand } 4762169cc62SArmin Le Grand else // Outermost SVG element 477ddde725dSArmin Le Grand { 4782169cc62SArmin Le Grand double fW = 0.0; // effective value depends on viewBox 4792169cc62SArmin Le Grand double fH = 0.0; 480ddde725dSArmin Le Grand 481ddde725dSArmin Le Grand // Svg defines that a negative value is an error and that 0.0 disables rendering 4822169cc62SArmin Le Grand // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive' 4832169cc62SArmin Le Grand const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0)); 4842169cc62SArmin Le Grand const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0)); 4852169cc62SArmin Le Grand if(!bWidthInvalid && !bHeightInvalid) 486ddde725dSArmin Le Grand { 4872169cc62SArmin Le Grand basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox 488ddde725dSArmin Le Grand if(getViewBox()) 489ddde725dSArmin Le Grand { 4902169cc62SArmin Le Grand // SVG 1.1 defines in section 7.7 that a negative value for width or height 4912169cc62SArmin Le Grand // in viewBox is an error and that 0.0 disables rendering 4922169cc62SArmin Le Grand const double fViewBoxWidth = getViewBox()->getWidth(); 4932169cc62SArmin Le Grand const double fViewBoxHeight = getViewBox()->getHeight(); 4942169cc62SArmin Le Grand if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0)) 495ddde725dSArmin Le Grand { 4962169cc62SArmin Le Grand // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height 4972169cc62SArmin Le Grand // or if one or both of them is relative by the width and height of the viewBox 4982169cc62SArmin Le Grand // see SVG 1.1 section 7.12 4992169cc62SArmin Le Grand const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 5002169cc62SArmin Le Grand const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 5012169cc62SArmin Le Grand if(bWidthIsAbsolute && bHeightIsAbsolute) 502ddde725dSArmin Le Grand { 5032169cc62SArmin Le Grand fW =getWidth().solveNonPercentage(*this); 5042169cc62SArmin Le Grand fH =getHeight().solveNonPercentage(*this); 5052169cc62SArmin Le Grand } 5062169cc62SArmin Le Grand else if (bWidthIsAbsolute) 5072169cc62SArmin Le Grand { 5082169cc62SArmin Le Grand fW = getWidth().solveNonPercentage(*this); 5092169cc62SArmin Le Grand fH = fW * fViewBoxWidth / fViewBoxHeight ; 5102169cc62SArmin Le Grand } 5112169cc62SArmin Le Grand else if (bHeightIsAbsolute) 5122169cc62SArmin Le Grand { 5132169cc62SArmin Le Grand fH = getHeight().solveNonPercentage(*this); 5142169cc62SArmin Le Grand fW = fH * fViewBoxWidth / fViewBoxHeight ; 515ddde725dSArmin Le Grand } 516ddde725dSArmin Le Grand else 517ddde725dSArmin Le Grand { 5182169cc62SArmin Le Grand fW = fViewBoxWidth; 5192169cc62SArmin Le Grand fH = fViewBoxHeight; 520ddde725dSArmin Le Grand } 5212169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 5222169cc62SArmin Le Grand aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); 5232169cc62SArmin Le Grand 5242169cc62SArmin Le Grand // create mapping 5252169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, 5262169cc62SArmin Le Grand // then the effect is as if a value of 'xMidYMid meet' were specified. 5272169cc62SArmin Le Grand SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); 5282169cc62SArmin Le Grand const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; 5292169cc62SArmin Le Grand 5302169cc62SArmin Le Grand basegfx::B2DHomMatrix aViewBoxMapping; 5312169cc62SArmin Le Grand aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); 5322169cc62SArmin Le Grand // no need to check ratio here for slice, the outermost Svg will 5332169cc62SArmin Le Grand // be clipped anyways (see below) 534ddde725dSArmin Le Grand 535ddde725dSArmin Le Grand // scale content to viewBox definitions 536ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 537ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 538ddde725dSArmin Le Grand aViewBoxMapping, 539ddde725dSArmin Le Grand aSequence)); 540ddde725dSArmin Le Grand 541ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 542ddde725dSArmin Le Grand } 543ddde725dSArmin Le Grand } 5442169cc62SArmin Le Grand else // no viewbox 5452169cc62SArmin Le Grand { 5462169cc62SArmin Le Grand // There exists no parent to resolve relative width or height. 5472169cc62SArmin Le Grand // Use child size as fallback. 5482169cc62SArmin Le Grand const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 5492169cc62SArmin Le Grand const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 5502169cc62SArmin Le Grand if (bWidthIsAbsolute && bHeightIsAbsolute) 5512169cc62SArmin Le Grand { 5522169cc62SArmin Le Grand fW =getWidth().solveNonPercentage(*this); 5532169cc62SArmin Le Grand fH =getHeight().solveNonPercentage(*this); 5542169cc62SArmin Le Grand 5552169cc62SArmin Le Grand } 5562169cc62SArmin Le Grand else 5572169cc62SArmin Le Grand { 5582169cc62SArmin Le Grand const basegfx::B2DRange aChildRange( 5592169cc62SArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 5602169cc62SArmin Le Grand aSequence, 5612169cc62SArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 5622169cc62SArmin Le Grand const double fChildWidth(aChildRange.getWidth()); 5632169cc62SArmin Le Grand const double fChildHeight(aChildRange.getHeight()); 5642169cc62SArmin Le Grand fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth; 5652169cc62SArmin Le Grand fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight; 5662169cc62SArmin Le Grand } 5672169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 5682169cc62SArmin Le Grand aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); 5692169cc62SArmin Le Grand } 570ddde725dSArmin Le Grand 571ddde725dSArmin Le Grand // to be completely correct in Svg sense it is necessary to clip 572ddde725dSArmin Le Grand // the whole content to the given canvas. I choose here to do this 573ddde725dSArmin Le Grand // initially despite I found various examples of Svg files out there 574ddde725dSArmin Le Grand // which have no correct values for this clipping. It's correct 575ddde725dSArmin Le Grand // due to the Svg spec. 576ddde725dSArmin Le Grand bool bDoCorrectCanvasClipping(true); 577ddde725dSArmin Le Grand 578ddde725dSArmin Le Grand if(bDoCorrectCanvasClipping) 579ddde725dSArmin Le Grand { 580ddde725dSArmin Le Grand // different from Svg we have the possibility with primitives to get 58141923119SArmin Le Grand // a correct bounding box for the geometry. Get it for evtl. taking action 582ddde725dSArmin Le Grand const basegfx::B2DRange aContentRange( 583ddde725dSArmin Le Grand drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( 584ddde725dSArmin Le Grand aSequence, 585ddde725dSArmin Le Grand drawinglayer::geometry::ViewInformation2D())); 586ddde725dSArmin Le Grand 58741923119SArmin Le Grand if(aSvgCanvasRange.isInside(aContentRange)) 588ddde725dSArmin Le Grand { 58941923119SArmin Le Grand // no clip needed, but an invisible HiddenGeometryPrimitive2D 59041923119SArmin Le Grand // to allow getting the full Svg range using the primitive mechanisms. 59141923119SArmin Le Grand // This is needed since e.g. an SdrObject using this as graphic will 59241923119SArmin Le Grand // create a mapping transformation to exactly map the content to it's 59341923119SArmin Le Grand // real life size 59441923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xLine( 59541923119SArmin Le Grand new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( 59641923119SArmin Le Grand basegfx::tools::createPolygonFromRect( 59741923119SArmin Le Grand aSvgCanvasRange), 59841923119SArmin Le Grand basegfx::BColor(0.0, 0.0, 0.0))); 59941923119SArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xHidden( 60041923119SArmin Le Grand new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( 60141923119SArmin Le Grand drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1))); 60241923119SArmin Le Grand 60341923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden); 60441923119SArmin Le Grand } 60541923119SArmin Le Grand else if(aSvgCanvasRange.overlaps(aContentRange)) 60641923119SArmin Le Grand { 60741923119SArmin Le Grand // Clip is necessary. This will make Svg images evtl. smaller 60841923119SArmin Le Grand // than wanted from Svg (the free space which may be around it is 60986e1cf34SPedro Giffuni // conform to the Svg spec), but avoids an expensive and unnecessary 61041923119SArmin Le Grand // clip. Keep the full Svg range here to get the correct mappings 61141923119SArmin Le Grand // to objects using this. Optimizations can be done in the processors 612ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xMask( 613ddde725dSArmin Le Grand new drawinglayer::primitive2d::MaskPrimitive2D( 614ddde725dSArmin Le Grand basegfx::B2DPolyPolygon( 615ddde725dSArmin Le Grand basegfx::tools::createPolygonFromRect( 616ddde725dSArmin Le Grand aSvgCanvasRange)), 617ddde725dSArmin Le Grand aSequence)); 618ddde725dSArmin Le Grand 619ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); 620ddde725dSArmin Le Grand } 62141923119SArmin Le Grand else 62241923119SArmin Le Grand { 62341923119SArmin Le Grand // not inside, no overlap. Empty Svg 62441923119SArmin Le Grand aSequence.realloc(0); 62541923119SArmin Le Grand } 626ddde725dSArmin Le Grand } 627ddde725dSArmin Le Grand 62841923119SArmin Le Grand if(aSequence.hasElements()) 629ddde725dSArmin Le Grand { 630ddde725dSArmin Le Grand // embed in transform primitive to scale to 1/100th mm 6312169cc62SArmin Le Grand // where 1 inch == 25.4 mm to get from Svg coordinates (px) to 6322169cc62SArmin Le Grand // drawinglayer coordinates 6332169cc62SArmin Le Grand const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH); 634ddde725dSArmin Le Grand const basegfx::B2DHomMatrix aTransform( 635ddde725dSArmin Le Grand basegfx::tools::createScaleB2DHomMatrix( 636ddde725dSArmin Le Grand fScaleTo100thmm, 637ddde725dSArmin Le Grand fScaleTo100thmm)); 638ddde725dSArmin Le Grand 639ddde725dSArmin Le Grand const drawinglayer::primitive2d::Primitive2DReference xTransform( 640ddde725dSArmin Le Grand new drawinglayer::primitive2d::TransformPrimitive2D( 641ddde725dSArmin Le Grand aTransform, 642ddde725dSArmin Le Grand aSequence)); 643ddde725dSArmin Le Grand 644ddde725dSArmin Le Grand aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); 645ddde725dSArmin Le Grand 64641923119SArmin Le Grand // append to result 64741923119SArmin Le Grand drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); 64841923119SArmin Le Grand } 649ddde725dSArmin Le Grand } 650ddde725dSArmin Le Grand } 651ddde725dSArmin Le Grand } 652ddde725dSArmin Le Grand } 653ddde725dSArmin Le Grand 654e92bb418SOliver-Rainer Wittmann const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const 655ddde725dSArmin Le Grand { 656ddde725dSArmin Le Grand if(getViewBox()) 657ddde725dSArmin Le Grand { 658e92bb418SOliver-Rainer Wittmann return *(getViewBox()); 659ddde725dSArmin Le Grand } 6602169cc62SArmin Le Grand else // viewport should be given by x, y, width, and height 661ddde725dSArmin Le Grand { 6622169cc62SArmin Le Grand // Extract known viewport data 6632169cc62SArmin Le Grand // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values 6642169cc62SArmin Le Grand if (getParent()) 6652169cc62SArmin Le Grand { 6662169cc62SArmin Le Grand // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 6672169cc62SArmin Le Grand // value 0.0 here is only to initialize variable 6682169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 6692169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 6702169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 6712169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 6722169cc62SArmin Le Grand 6732169cc62SArmin Le Grand // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 6742169cc62SArmin Le Grand bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); 6752169cc62SArmin Le Grand double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); 6762169cc62SArmin Le Grand 6772169cc62SArmin Le Grand bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); 6782169cc62SArmin Le Grand double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); 6792169cc62SArmin Le Grand 6802169cc62SArmin Le Grand if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) 6812169cc62SArmin Le Grand { 682e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(fX, fY, fX+fW, fY+fH); 6832169cc62SArmin Le Grand } 6842169cc62SArmin Le Grand else // try to resolve relative values 6852169cc62SArmin Le Grand { 6862169cc62SArmin Le Grand if (!bXIsAbsolute || !bWidthIsAbsolute) 6872169cc62SArmin Le Grand { 6882169cc62SArmin Le Grand // get width of enclosing svg and resolve percentage in x and width 6892169cc62SArmin Le Grand double fWReference(0.0); 6902169cc62SArmin Le Grand bool bHasFoundWidth(false); 6912169cc62SArmin Le Grand seekReferenceWidth(fWReference, bHasFoundWidth); 6922169cc62SArmin Le Grand // referenced values are already in 'user unit' 6932169cc62SArmin Le Grand if (!bXIsAbsolute && bHasFoundWidth) 6942169cc62SArmin Le Grand { 6952169cc62SArmin Le Grand fX = getX().getNumber() * 0.01 * fWReference; 6962169cc62SArmin Le Grand bXIsAbsolute = true; 6972169cc62SArmin Le Grand } 6982169cc62SArmin Le Grand if (!bWidthIsAbsolute && bHasFoundWidth) 6992169cc62SArmin Le Grand { 7002169cc62SArmin Le Grand fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; 7012169cc62SArmin Le Grand bWidthIsAbsolute = true; 7022169cc62SArmin Le Grand } 7032169cc62SArmin Le Grand } 7042169cc62SArmin Le Grand if (!bYIsAbsolute || !bHeightIsAbsolute) 7052169cc62SArmin Le Grand { 7062169cc62SArmin Le Grand // get height of enclosing svg and resolve percentage in y and height 7072169cc62SArmin Le Grand double fHReference(0.0); 7082169cc62SArmin Le Grand bool bHasFoundHeight(false); 7092169cc62SArmin Le Grand seekReferenceHeight(fHReference, bHasFoundHeight); 7102169cc62SArmin Le Grand // referenced values are already in 'user unit' 7112169cc62SArmin Le Grand if (!bYIsAbsolute && bHasFoundHeight) 7122169cc62SArmin Le Grand { 7132169cc62SArmin Le Grand fY = getY().getNumber() * 0.01 * fHReference; 7142169cc62SArmin Le Grand bYIsAbsolute = true; 7152169cc62SArmin Le Grand } 7162169cc62SArmin Le Grand if (!bHeightIsAbsolute && bHasFoundHeight) 7172169cc62SArmin Le Grand { 7182169cc62SArmin Le Grand fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; 7192169cc62SArmin Le Grand bHeightIsAbsolute = true; 7202169cc62SArmin Le Grand } 7212169cc62SArmin Le Grand } 7222169cc62SArmin Le Grand 7232169cc62SArmin Le Grand if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) 7242169cc62SArmin Le Grand { 725e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(fX, fY, fX+fW, fY+fH); 7262169cc62SArmin Le Grand } 7272169cc62SArmin Le Grand else // relative values could not be resolved, there exists no fallback 7282169cc62SArmin Le Grand { 7292169cc62SArmin Le Grand return SvgNode::getCurrentViewPort(); 7302169cc62SArmin Le Grand } 7312169cc62SArmin Le Grand } 7322169cc62SArmin Le Grand } 7332169cc62SArmin Le Grand else //outermost svg 7342169cc62SArmin Le Grand { 7352169cc62SArmin Le Grand // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2 7362169cc62SArmin Le Grand // But here it cannot be resolved and no fallback exists. 7372169cc62SArmin Le Grand // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. 7382169cc62SArmin Le Grand bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); 7392169cc62SArmin Le Grand double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); 7402169cc62SArmin Le Grand bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); 7412169cc62SArmin Le Grand double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); 7422169cc62SArmin Le Grand if (bWidthIsAbsolute && bHeightIsAbsolute) 7432169cc62SArmin Le Grand { 744e92bb418SOliver-Rainer Wittmann return basegfx::B2DRange(0.0, 0.0, fW, fH); 7452169cc62SArmin Le Grand } 7462169cc62SArmin Le Grand else // no fallback exists 7472169cc62SArmin Le Grand { 7482169cc62SArmin Le Grand return SvgNode::getCurrentViewPort(); 7492169cc62SArmin Le Grand } 7502169cc62SArmin Le Grand } 7512169cc62SArmin Le Grand // ToDo: Is it possible to decompose and use the bounding box of the childs, if even the 7522169cc62SArmin Le Grand // outermost svg has no information to resolve percentage? Is it worth, how expensive is it? 7532169cc62SArmin Le Grand 754ddde725dSArmin Le Grand } 755ddde725dSArmin Le Grand } 756ddde725dSArmin Le Grand 757ddde725dSArmin Le Grand } // end of namespace svgreader 758ddde725dSArmin Le Grand } // end of namespace svgio 759ddde725dSArmin Le Grand 760ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 761ddde725dSArmin Le Grand // eof 762