svgio/inc/svgio/svgreader/svgsvgnode.hxx | 10 svgio/inc/svgio/svgreader/svgtools.hxx | 8 svgio/source/svgreader/svgcirclenode.cxx | 2 svgio/source/svgreader/svgsvgnode.cxx | 459 +++++++++++++++++++++++-------- svgio/source/svgreader/svgtools.cxx | 65 +++- 5 files changed, 418 insertions(+), 126 deletions(-)
New commits: commit 8a9164f5f853db66b4453fc6fb798acf0a88a238 Author: Armin Le Grand <[email protected]> Date: Tue Aug 13 16:58:52 2013 +0000 i122600 Added patch from Regina that fixes a bunch of tasks (list see in task itself) and a reression/crash Patch by: regina Review by: ALG diff --git a/svgio/inc/svgio/svgreader/svgsvgnode.hxx b/svgio/inc/svgio/svgreader/svgsvgnode.hxx index a72fcf7..134dabe 100644 --- a/svgio/inc/svgio/svgreader/svgsvgnode.hxx +++ b/svgio/inc/svgio/svgreader/svgsvgnode.hxx @@ -56,7 +56,15 @@ namespace svgio virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; - /// InfoProvider support for % values + /// Seeks width and height of viewport, which is current before the new viewport is set. + // needed for percentage unit in x, y, width or height + virtual void seekReferenceWidth(double& fWidth, bool& bHasFound) const; + virtual void seekReferenceHeight(double& fHeight, bool& bHasFound) const; + + /// InfoProvider support for % values in childs + // The returned 'CurrentViewPort' is the viewport as it is set by this svg element + // and as it is needed to resolve relative values in childs + // The method does not check for invalid width and height virtual const basegfx::B2DRange* getCurrentViewPort() const; /// viewBox content diff --git a/svgio/inc/svgio/svgreader/svgtools.hxx b/svgio/inc/svgio/svgreader/svgtools.hxx index 3933d3b..3efc337 100644 --- a/svgio/inc/svgio/svgreader/svgtools.hxx +++ b/svgio/inc/svgio/svgreader/svgtools.hxx @@ -40,6 +40,9 @@ namespace svgio void myAssert(const rtl::OUString& rMessage); #endif +// recommended value for this devise dependend unit, see CSS2 section 4.3.2 Lenghts +#define F_SVG_PIXEL_PER_INCH 90.0 + // common non-token strings struct commonStrings { @@ -126,7 +129,12 @@ namespace svgio bool isPositive() const; + // Only usable in cases, when the unit is not Unit_percent, otherwise use method solve + double solveNonPercentage(const InfoProvider& rInfoProvider) const; + double solve(const InfoProvider& rInfoProvider, NumberType aNumberType = length) const; + + }; typedef ::std::vector< SvgNumber > SvgNumberVector; diff --git a/svgio/source/svgreader/svgcirclenode.cxx b/svgio/source/svgreader/svgcirclenode.cxx index e13c150..261f97c 100644 --- a/svgio/source/svgreader/svgcirclenode.cxx +++ b/svgio/source/svgreader/svgcirclenode.cxx @@ -128,7 +128,7 @@ namespace svgio if(pStyle && getR().isSet()) { - const double fR(getR().solve(*this, xcoordinate)); + const double fR(getR().solve(*this, length)); if(fR > 0.0) { diff --git a/svgio/source/svgreader/svgsvgnode.cxx b/svgio/source/svgreader/svgsvgnode.cxx index 95b15fb..fb46d3e 100644 --- a/svgio/source/svgreader/svgsvgnode.cxx +++ b/svgio/source/svgreader/svgsvgnode.cxx @@ -162,6 +162,91 @@ namespace svgio } } + void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const + { + if (!getParent() || bHasFound) + { + return; + } + const SvgSvgNode* pParentSvgSvgNode = 0; + // enclosing svg might have relative width, need to cumulate them till they are + // resolved somewhere up in the node tree + double fPercentage(1.0); + for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) + { + // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition + pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); + if (pParentSvgSvgNode) + { + if (pParentSvgSvgNode->getViewBox()) + { + // viewbox values are already in 'user unit'. + fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage; + bHasFound = true; + } + else + { + // take absolute value or cummulate percentage + if (pParentSvgSvgNode->getWidth().isSet()) + { + if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit()) + { + fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01; + } + else + { + fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; + bHasFound = true; + } + } // not set => width=100% => factor 1, no need for else + } + } + } + } + + void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const + { + if (!getParent() || bHasFound) + { + return; + } + const SvgSvgNode* pParentSvgSvgNode = 0; + // enclosing svg might have relative width and height, need to cumulate them till they are + // resolved somewhere up in the node tree + double fPercentage(1.0); + for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent()) + { + // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition + pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); + if (pParentSvgSvgNode) + { + if (pParentSvgSvgNode->getViewBox()) + { + // viewbox values are already in 'user unit'. + fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage; + bHasFound = true; + } + else + { + // take absolute value or cummulate percentage + if (pParentSvgSvgNode->getHeight().isSet()) + { + if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit()) + { + fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01; + } + else + { + fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage; + bHasFound = true; + } + } // not set => height=100% => factor 1, no need for else + } + } + } + } + +// ToDo: Consider attribute overflow in method decomposeSvgNode void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const { drawinglayer::primitive2d::Primitive2DSequence aSequence; @@ -173,13 +258,7 @@ namespace svgio { if(getParent()) { - const bool bWidthIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit()); - const bool bHeightIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit()); - const SvgSvgNode* pParentSvgSvgNode = 0; - double fW(0.0); - double fH(0.0); - - // #122594# if width/height is not given, it's 100% (see 5.1.2 The svg element in SVG1.1 spec). + // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec). // If it is relative, the question is to what. The previous implementatin assumed relative to the // local ViewBox which is implied by (4.2 Basic data types): // @@ -190,56 +269,92 @@ namespace svgio // units in general), and (b) when a percentage length value represents a percentage of the // bounding box width or height on a given object (refer to the section that describes object // bounding box units)." - // - // This is not closer specified for the SVG element itself as non-outmost element, but comparisons - // with common browsers shows that it's mostly interpreted relative to the viewBox of the parent. - // Adding code to search the parent SVG element and calculating width/height relative to it's - // viewBox width/height (and no longer to the local viewBox). - if(bWidthIsRelative || bHeightIsRelative) + + // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport + // of the parent, and so does the new implementation. + + // Extract known viewport data + // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values + + // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 + // value 0.0 here is only to initialize variable + bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); + double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); + + bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); + double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); + + // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 + bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); + double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); + + bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); + double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); + + if ( !bXIsAbsolute || !bWidthIsAbsolute) { - for(const SvgNode* pParent = getParent(); pParent && !pParentSvgSvgNode; pParent = pParent->getParent()) + // get width of enclosing svg and resolve percentage in x and width; + double fWReference(0.0); + bool bHasFoundWidth(false); + seekReferenceWidth(fWReference, bHasFoundWidth); + if (!bHasFoundWidth) { - pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent); + // Even outermost svg has not all information to resolve relative values, + // I use content itself as fallback to set missing values for viewport + // Any better idea for such ill structures svg documents? + const basegfx::B2DRange aChildRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + aSequence, + drawinglayer::geometry::ViewInformation2D())); + fWReference = aChildRange.getWidth(); } - } - - if(bWidthIsRelative) - { - fW = getWidth().isSet() ? getWidth().getNumber() * 0.01 : 1.0; - - if(pParentSvgSvgNode) + // referenced values are already in 'user unit' + if (!bXIsAbsolute) { - fW *= pParentSvgSvgNode->getViewBox()->getWidth(); + fX = getX().getNumber() * 0.01 * fWReference; + } + if (!bWidthIsAbsolute) + { + fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; } - } - else - { - fW = getWidth().solve(*this, xcoordinate); } - if(bHeightIsRelative) + if ( !bYIsAbsolute || !bHeightIsAbsolute) { - fH = getHeight().isSet() ? getHeight().getNumber() * 0.01 : 1.0; + // get height of enclosing svg and resolve percentage in y and height + double fHReference(0.0); + bool bHasFoundHeight(false); + seekReferenceHeight(fHReference, bHasFoundHeight); + if (!bHasFoundHeight) + { + // Even outermost svg has not all information to resolve relative values, + // I use content itself as fallback to set missing values for viewport + // Any better idea for such ill structures svg documents? + const basegfx::B2DRange aChildRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + aSequence, + drawinglayer::geometry::ViewInformation2D())); + fHReference = aChildRange.getHeight(); + } - if(pParentSvgSvgNode) + // referenced values are already in 'user unit' + if (!bYIsAbsolute) { - fH *= pParentSvgSvgNode->getViewBox()->getHeight(); + fY = getY().getNumber() * 0.01 * fHReference; + } + if (!bHeightIsAbsolute) + { + fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; } - } - else - { - fH = getHeight().solve(*this, ycoordinate); } if(getViewBox()) { - // Svg defines that with no width or no height the viewBox content is empty, - // so both need to exist - if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) + // SVG 1.1 defines in section 7.7 that a negative value for width or height + // in viewBox is an error and that 0.0 disables rendering + if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0)) { - // create target range homing x,y, width and height as given - const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); - const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + // create target range homing x,y, width and height as calculated above const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH); if(aTarget.equal(*getViewBox())) @@ -250,63 +365,44 @@ namespace svgio else { // create mapping - const SvgAspectRatio& rRatio = getSvgAspectRatio(); + // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, + // then the effect is as if a value of 'xMidYMid meet' were specified. + SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); + const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; - if(rRatio.isSet()) + // let mapping be created from SvgAspectRatio + const basegfx::B2DHomMatrix aEmbeddingTransform( + rRatio.createMapping(aTarget, *getViewBox())); + + // prepare embedding in transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aSequence)); + + if(rRatio.isMeetOrSlice()) { - // let mapping be created from SvgAspectRatio - const basegfx::B2DHomMatrix aEmbeddingTransform( - rRatio.createMapping(aTarget, *getViewBox())); - - // prepare embedding in transformation - const drawinglayer::primitive2d::Primitive2DReference xRef( - new drawinglayer::primitive2d::TransformPrimitive2D( - aEmbeddingTransform, - aSequence)); - - if(rRatio.isMeetOrSlice()) - { - // embed in transformation - drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); - } - else - { - // need to embed in MaskPrimitive2D, too - const drawinglayer::primitive2d::Primitive2DReference xMask( - new drawinglayer::primitive2d::MaskPrimitive2D( - basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), - drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); - - drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); - } + // embed in transformation + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); } else { - // choose default mapping - const basegfx::B2DHomMatrix aEmbeddingTransform( - rRatio.createLinearMapping( - aTarget, *getViewBox())); - - // embed in transformation - const drawinglayer::primitive2d::Primitive2DReference xTransform( - new drawinglayer::primitive2d::TransformPrimitive2D( - aEmbeddingTransform, - aSequence)); + // need to embed in MaskPrimitive2D, too + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), + drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); - drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xTransform); + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); } } } } - else + else // no viewBox attribute { // Svg defines that a negative value is an error and that 0.0 disables rendering if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) { - // check if we have a x,y position - const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); - const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); - if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) { // embed in transform @@ -331,40 +427,64 @@ namespace svgio } } } - else + else // Outermost SVG element { - // Outermost SVG element; create target range homing width and height as given. - // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback - // width and height of din A 4 (21 x 29,7 cm) - double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : (210.0 * 3.543307)); - double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : (297.0 * 3.543307)); + double fW = 0.0; // effective value depends on viewBox + double fH = 0.0; // Svg defines that a negative value is an error and that 0.0 disables rendering - if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) + // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive' + const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0)); + const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0)); + if(!bWidthInvalid && !bHeightInvalid) { - const basegfx::B2DRange aSvgCanvasRange(0.0, 0.0, fW, fH); - + basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox if(getViewBox()) { - if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) + // SVG 1.1 defines in section 7.7 that a negative value for width or height + // in viewBox is an error and that 0.0 disables rendering + const double fViewBoxWidth = getViewBox()->getWidth(); + const double fViewBoxHeight = getViewBox()->getHeight(); + if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0)) { - // create mapping - const SvgAspectRatio& rRatio = getSvgAspectRatio(); - basegfx::B2DHomMatrix aViewBoxMapping; - - if(rRatio.isSet()) + // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height + // or if one or both of them is relative by the width and height of the viewBox + // see SVG 1.1 section 7.12 + const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); + const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); + if(bWidthIsAbsolute && bHeightIsAbsolute) { - // let mapping be created from SvgAspectRatio - aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); - - // no need to check ratio here for slice, the outermost Svg will - // be clipped anyways (see below) + fW =getWidth().solveNonPercentage(*this); + fH =getHeight().solveNonPercentage(*this); + } + else if (bWidthIsAbsolute) + { + fW = getWidth().solveNonPercentage(*this); + fH = fW * fViewBoxWidth / fViewBoxHeight ; + } + else if (bHeightIsAbsolute) + { + fH = getHeight().solveNonPercentage(*this); + fW = fH * fViewBoxWidth / fViewBoxHeight ; } else { - // choose default mapping - aViewBoxMapping = rRatio.createLinearMapping(aSvgCanvasRange, *getViewBox()); + fW = fViewBoxWidth; + fH = fViewBoxHeight; } + // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. + aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); + + // create mapping + // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified, + // then the effect is as if a value of 'xMidYMid meet' were specified. + SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true); + const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault; + + basegfx::B2DHomMatrix aViewBoxMapping; + aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); + // no need to check ratio here for slice, the outermost Svg will + // be clipped anyways (see below) // scale content to viewBox definitions const drawinglayer::primitive2d::Primitive2DReference xTransform( @@ -375,6 +495,32 @@ namespace svgio aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); } } + else // no viewbox + { + // There exists no parent to resolve relative width or height. + // Use child size as fallback. + const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); + const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); + if (bWidthIsAbsolute && bHeightIsAbsolute) + { + fW =getWidth().solveNonPercentage(*this); + fH =getHeight().solveNonPercentage(*this); + + } + else + { + const basegfx::B2DRange aChildRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + aSequence, + drawinglayer::geometry::ViewInformation2D())); + const double fChildWidth(aChildRange.getWidth()); + const double fChildHeight(aChildRange.getHeight()); + fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth; + fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight; + } + // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. + aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH); + } // to be completely correct in Svg sense it is necessary to clip // the whole content to the given canvas. I choose here to do this @@ -436,9 +582,9 @@ namespace svgio if(aSequence.hasElements()) { // embed in transform primitive to scale to 1/100th mm - // where 1 mm == 3.543307 px to get from Svg coordinates to - // drawinglayer ones - const double fScaleTo100thmm(100.0 / 3.543307); + // where 1 inch == 25.4 mm to get from Svg coordinates (px) to + // drawinglayer coordinates + const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH); const basegfx::B2DHomMatrix aTransform( basegfx::tools::createScaleB2DHomMatrix( fScaleTo100thmm, @@ -465,9 +611,100 @@ namespace svgio { return getViewBox(); } - else + else // viewport should be given by x, y, width, and height { - return SvgNode::getCurrentViewPort(); + // Extract known viewport data + // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values + if (getParent()) + { + // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2 + // value 0.0 here is only to initialize variable + bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); + double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); + bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); + double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); + + // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2 + bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet()); + double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0); + + bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet()); + double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0); + + if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) + { + return &basegfx::B2DRange(fX, fY, fX+fW, fY+fH); + } + else // try to resolve relative values + { + if (!bXIsAbsolute || !bWidthIsAbsolute) + { + // get width of enclosing svg and resolve percentage in x and width + double fWReference(0.0); + bool bHasFoundWidth(false); + seekReferenceWidth(fWReference, bHasFoundWidth); + // referenced values are already in 'user unit' + if (!bXIsAbsolute && bHasFoundWidth) + { + fX = getX().getNumber() * 0.01 * fWReference; + bXIsAbsolute = true; + } + if (!bWidthIsAbsolute && bHasFoundWidth) + { + fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference; + bWidthIsAbsolute = true; + } + } + if (!bYIsAbsolute || !bHeightIsAbsolute) + { + // get height of enclosing svg and resolve percentage in y and height + double fHReference(0.0); + bool bHasFoundHeight(false); + seekReferenceHeight(fHReference, bHasFoundHeight); + // referenced values are already in 'user unit' + if (!bYIsAbsolute && bHasFoundHeight) + { + fY = getY().getNumber() * 0.01 * fHReference; + bYIsAbsolute = true; + } + if (!bHeightIsAbsolute && bHasFoundHeight) + { + fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference; + bHeightIsAbsolute = true; + } + } + + if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute) + { + return &basegfx::B2DRange(fX, fY, fX+fW, fY+fH); + } + else // relative values could not be resolved, there exists no fallback + { + return SvgNode::getCurrentViewPort(); + } + } + } + else //outermost svg + { + // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2 + // But here it cannot be resolved and no fallback exists. + // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element. + bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit()); + double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0); + bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit()); + double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0); + if (bWidthIsAbsolute && bHeightIsAbsolute) + { + return &basegfx::B2DRange(0.0, 0.0, fW, fH); + } + else // no fallback exists + { + return SvgNode::getCurrentViewPort(); + } + } +// ToDo: Is it possible to decompose and use the bounding box of the childs, if even the +// outermost svg has no information to resolve percentage? Is it worth, how expensive is it? + } } diff --git a/svgio/source/svgreader/svgtools.cxx b/svgio/source/svgreader/svgtools.cxx index 7eb1802..2dcc229 100644 --- a/svgio/source/svgreader/svgtools.cxx +++ b/svgio/source/svgreader/svgtools.cxx @@ -156,7 +156,7 @@ namespace svgio return aRetval; } - double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const + double SvgNumber::solveNonPercentage(const InfoProvider& rInfoProvider) const { if(isSet()) { @@ -187,17 +187,53 @@ namespace svgio switch(meUnit) { - case Unit_pt: fRetval *= 1.25; break; - case Unit_pc: fRetval *= 15.0; break; - case Unit_cm: fRetval *= 35.43307; break; - case Unit_mm: fRetval *= 3.543307; break; - case Unit_in: fRetval *= 90.0; break; + case Unit_pt: fRetval *= F_SVG_PIXEL_PER_INCH / 72.0; break; + case Unit_pc: fRetval *= F_SVG_PIXEL_PER_INCH / 6.0; break; + case Unit_cm: fRetval *= F_SVG_PIXEL_PER_INCH / 2.54; break; + case Unit_mm: fRetval *= 0.1 * F_SVG_PIXEL_PER_INCH / 2.54; break; + case Unit_in: fRetval *= F_SVG_PIXEL_PER_INCH; break; default: break; } return fRetval; break; } + default: + { + OSL_ENSURE(false, "Do not use with percentage! "); + return 0.0; + break; + } + } + } + + /// not set + OSL_ENSURE(false, "SvgNumber not set (!)"); + return 0.0; + } + + double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const + { + if(isSet()) + { + switch(meUnit) + { + case Unit_px: + { + return mfNumber; + break; + } + case Unit_pt: + case Unit_pc: + case Unit_cm: + case Unit_mm: + case Unit_in: + case Unit_em: + case Unit_ex: + { + return solveNonPercentage( rInfoProvider); + break; + } case Unit_percent: { double fRetval(mfNumber * 0.01); @@ -205,12 +241,15 @@ namespace svgio if(!pViewPort) { +#ifdef DBG_UTIL + myAssert(rtl::OUString::createFromAscii("Design error, this case should have been handled in the caller")); +#endif // no viewPort, assume a normal page size (A4) static basegfx::B2DRange aDinA4Range( 0.0, 0.0, - 210.0 * 3.543307, - 297.0 * 3.543307); + 210.0 * F_SVG_PIXEL_PER_INCH / 2.54, + 297.0 * F_SVG_PIXEL_PER_INCH / 2.54); pViewPort = &aDinA4Range; } @@ -924,11 +963,11 @@ namespace svgio if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen)) { - return basegfx::B2DRange( - aMinX.solve(rInfoProvider, xcoordinate), - aMinY.solve(rInfoProvider, ycoordinate), - aWidth.solve(rInfoProvider, xcoordinate), - aHeight.solve(rInfoProvider, ycoordinate)); + double fX(aMinX.solve(rInfoProvider, xcoordinate)); + double fY(aMinY.solve(rInfoProvider, ycoordinate)); + double fW(aWidth.solve(rInfoProvider,xcoordinate)); + double fH(aHeight.solve(rInfoProvider,ycoordinate)); + return basegfx::B2DRange(fX,fY,fX+fW,fY+fH); } } }
_______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
