[Libreoffice-commits] core.git: Branch 'aoo/trunk' - svgio/inc svgio/source
Armin Le Grand
alg at apache.org
Tue Aug 13 11:11:00 PDT 2013
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 <alg at apache.org>
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);
}
}
}
More information about the Libreoffice-commits
mailing list