diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMEllipseElement.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMEllipseElement.java
index 9c85e0397..253377330 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMEllipseElement.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMEllipseElement.java
@@ -35,7 +35,7 @@
*/
public class SVGOMEllipseElement extends SVGGraphicsElement implements SVGEllipseElement {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 2L;
/**
* Table mapping XML attribute names to TraitInformation objects.
@@ -63,12 +63,12 @@ public class SVGOMEllipseElement extends SVGGraphicsElement implements SVGEllips
/**
* The 'rx' attribute value.
*/
- protected SVGOMAnimatedLength rx;
+ protected AbstractSVGAnimatedLength rx;
/**
* The 'ry' attribute value.
*/
- protected SVGOMAnimatedLength ry;
+ protected AbstractSVGAnimatedLength ry;
/**
* Creates a new SVGOMEllipseElement object.
@@ -104,8 +104,52 @@ private void initializeLiveAttributes() {
AbstractSVGAnimatedLength.HORIZONTAL_LENGTH, false);
cy = createLiveAnimatedLength(null, SVG_CY_ATTRIBUTE, SVG_ELLIPSE_CY_DEFAULT_VALUE,
AbstractSVGAnimatedLength.VERTICAL_LENGTH, false);
- rx = createLiveAnimatedLength(null, SVG_RX_ATTRIBUTE, null, AbstractSVGAnimatedLength.HORIZONTAL_LENGTH, true);
- ry = createLiveAnimatedLength(null, SVG_RY_ATTRIBUTE, null, AbstractSVGAnimatedLength.VERTICAL_LENGTH, true);
+ rx = new AbstractSVGAnimatedLength(this, null, SVG_RX_ATTRIBUTE, AbstractSVGAnimatedLength.HORIZONTAL_LENGTH,
+ true) {
+ @Override
+ protected String getDefaultValue() {
+ String defval = getAttribute(SVG_RY_ATTRIBUTE).trim();
+ if (defval.isEmpty() || SVG_AUTO_VALUE.equalsIgnoreCase(defval)) {
+ defval = "0";
+ }
+ return defval;
+ }
+
+ @Override
+ protected void attrChanged() {
+ super.attrChanged();
+ AbstractSVGAnimatedLength ry = (AbstractSVGAnimatedLength) getRy();
+ if (isSpecified() && !ry.isSpecified()) {
+ ry.attrChanged();
+ }
+ }
+ };
+ ry = new AbstractSVGAnimatedLength(this, null, SVG_RY_ATTRIBUTE, AbstractSVGAnimatedLength.VERTICAL_LENGTH,
+ true) {
+ @Override
+ protected String getDefaultValue() {
+ String defval = getAttribute(SVG_RX_ATTRIBUTE).trim();
+ if (defval.isEmpty() || SVG_AUTO_VALUE.equalsIgnoreCase(defval)) {
+ defval = "0";
+ }
+ return defval;
+ }
+
+ @Override
+ protected void attrChanged() {
+ super.attrChanged();
+ AbstractSVGAnimatedLength rx = (AbstractSVGAnimatedLength) getRx();
+ if (isSpecified() && !rx.isSpecified()) {
+ rx.attrChanged();
+ }
+ }
+ };
+
+ liveAttributeValues.put(null, SVG_RX_ATTRIBUTE, rx);
+ liveAttributeValues.put(null, SVG_RY_ATTRIBUTE, ry);
+ AnimatedAttributeListener l = ((SVGOMDocument) ownerDocument).getAnimatedAttributeListener();
+ rx.addAnimatedAttributeListener(l);
+ ry.addAnimatedAttributeListener(l);
}
/**
diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRadialGradientElement.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRadialGradientElement.java
index 9a405d7aa..b8f8c8b3b 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRadialGradientElement.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRadialGradientElement.java
@@ -18,7 +18,6 @@
*/
package io.sf.carte.echosvg.anim.dom;
-import org.w3c.dom.Attr;
import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGAnimatedLength;
import org.w3c.dom.svg.SVGRadialGradientElement;
@@ -117,22 +116,22 @@ private void initializeLiveAttributes() {
false) {
@Override
protected String getDefaultValue() {
- Attr attr = getAttributeNodeNS(null, SVG_CX_ATTRIBUTE);
- if (attr == null) {
- return SVG_RADIAL_GRADIENT_CX_DEFAULT_VALUE;
+ String defval = getAttribute(SVG_CX_ATTRIBUTE).trim();
+ if (defval.isEmpty()) {
+ defval = SVG_RADIAL_GRADIENT_CX_DEFAULT_VALUE;
}
- return attr.getValue();
+ return defval;
}
};
fy = new AbstractSVGAnimatedLength(this, null, SVG_FY_ATTRIBUTE, AbstractSVGAnimatedLength.VERTICAL_LENGTH,
false) {
@Override
protected String getDefaultValue() {
- Attr attr = getAttributeNodeNS(null, SVG_CY_ATTRIBUTE);
- if (attr == null) {
- return SVG_RADIAL_GRADIENT_CY_DEFAULT_VALUE;
+ String defval = getAttribute(SVG_CY_ATTRIBUTE).trim();
+ if (defval.isEmpty()) {
+ defval = SVG_RADIAL_GRADIENT_CY_DEFAULT_VALUE;
}
- return attr.getValue();
+ return defval;
}
};
diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRectElement.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRectElement.java
index 2a865f148..c93777a9d 100644
--- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRectElement.java
+++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMRectElement.java
@@ -18,7 +18,6 @@
*/
package io.sf.carte.echosvg.anim.dom;
-import org.w3c.dom.Attr;
import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGAnimatedLength;
import org.w3c.dom.svg.SVGRectElement;
@@ -126,11 +125,11 @@ private void initializeLiveAttributes() {
true) {
@Override
protected String getDefaultValue() {
- Attr attr = getAttributeNodeNS(null, SVG_RY_ATTRIBUTE);
- if (attr == null) {
- return "0";
+ String defval = getAttribute(SVG_RY_ATTRIBUTE).trim();
+ if (defval.isEmpty() || SVG_AUTO_VALUE.equalsIgnoreCase(defval)) {
+ defval = "0";
}
- return attr.getValue();
+ return defval;
}
@Override
@@ -146,11 +145,11 @@ protected void attrChanged() {
true) {
@Override
protected String getDefaultValue() {
- Attr attr = getAttributeNodeNS(null, SVG_RX_ATTRIBUTE);
- if (attr == null) {
- return "0";
+ String defval = getAttribute(SVG_RX_ATTRIBUTE).trim();
+ if (defval.isEmpty() || SVG_AUTO_VALUE.equalsIgnoreCase(defval)) {
+ defval = "0";
}
- return attr.getValue();
+ return defval;
}
@Override
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGCircleElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGCircleElementBridge.java
index 931806e2c..42658902b 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGCircleElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGCircleElementBridge.java
@@ -75,29 +75,19 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
// 'cx' attribute - default is 0
AbstractSVGAnimatedLength _cx = (AbstractSVGAnimatedLength) ce.getCx();
- float cx = _cx.getCheckedValue();
+ float cx = safeAnimatedCheckedValue(_cx, 0f);
// 'cy' attribute - default is 0
AbstractSVGAnimatedLength _cy = (AbstractSVGAnimatedLength) ce.getCy();
- float cy = _cy.getCheckedValue();
+ float cy = safeAnimatedCheckedValue(_cy, 0f);
// 'r' attribute - default is 0 (SVG2)
AbstractSVGAnimatedLength _r = (AbstractSVGAnimatedLength) ce.getR();
- float r;
- try {
- r = _r.getCheckedValue();
- } catch (LiveAttributeException ex) {
- r = 0f;
- BridgeException be = new BridgeException(ctx, ex);
- if (ctx.userAgent == null) {
- throw be;
- }
- ctx.userAgent.displayError(be);
- }
+ float r = safeAnimatedCheckedValue(_r, 0f);
float x = cx - r;
float y = cy - r;
- float w = r * 2;
+ float w = r * 2f;
shapeNode.setShape(new Ellipse2D.Float(x, y, w, w));
} catch (LiveAttributeException ex) {
throw new BridgeException(ctx, ex);
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGEllipseElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGEllipseElementBridge.java
index ca5da2b20..668e62701 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGEllipseElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGEllipseElementBridge.java
@@ -75,11 +75,11 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
// 'cx' attribute - default is 0
AbstractSVGAnimatedLength _cx = (AbstractSVGAnimatedLength) ee.getCx();
- float cx = _cx.getCheckedValue();
+ float cx = safeAnimatedCheckedValue(_cx, 0f);
// 'cy' attribute - default is 0
AbstractSVGAnimatedLength _cy = (AbstractSVGAnimatedLength) ee.getCy();
- float cy = _cy.getCheckedValue();
+ float cy = safeAnimatedCheckedValue(_cy, 0f);
// 'rx' attribute - default is auto (SVG2)
boolean rxAuto = false;
@@ -121,7 +121,7 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
rx = ry;
}
- shapeNode.setShape(new Ellipse2D.Float(cx - rx, cy - ry, rx * 2, ry * 2));
+ shapeNode.setShape(new Ellipse2D.Float(cx - rx, cy - ry, rx * 2f, ry * 2f));
} catch (LiveAttributeException ex) {
throw new BridgeException(ctx, ex);
}
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGRectElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGRectElementBridge.java
index 24b89494e..443b2657b 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGRectElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGRectElementBridge.java
@@ -77,39 +77,19 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
// 'x' attribute - default is 0
AbstractSVGAnimatedLength _x = (AbstractSVGAnimatedLength) re.getX();
- float x = _x.getCheckedValue();
+ float x = safeAnimatedCheckedValue(_x, 0f);
// 'y' attribute - default is 0
AbstractSVGAnimatedLength _y = (AbstractSVGAnimatedLength) re.getY();
- float y = _y.getCheckedValue();
+ float y = safeAnimatedCheckedValue(_y, 0f);
- // 'width' attribute - required
+ // 'width' attribute - default is 0
AbstractSVGAnimatedLength _width = (AbstractSVGAnimatedLength) re.getWidth();
- float w;
- try {
- w = _width.getCheckedValue();
- } catch (LiveAttributeException ex) {
- w = 0;
- BridgeException be = new BridgeException(ctx, ex);
- if (ctx.userAgent == null) {
- throw be;
- }
- ctx.userAgent.displayError(be);
- }
+ float w = safeAnimatedCheckedValue(_width, 0f);
- // 'height' attribute - required
+ // 'height' attribute - default is 0
AbstractSVGAnimatedLength _height = (AbstractSVGAnimatedLength) re.getHeight();
- float h;
- try {
- h = _height.getCheckedValue();
- } catch (LiveAttributeException ex) {
- h = 0;
- BridgeException be = new BridgeException(ctx, ex);
- if (ctx.userAgent == null) {
- throw be;
- }
- ctx.userAgent.displayError(be);
- }
+ float h = safeAnimatedCheckedValue(_height, 0f);
// 'rx' attribute - default is 0
boolean rxAuto = false;
@@ -118,7 +98,7 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
try {
rx = _rx.getCheckedValue();
} catch (LiveAttributeException ex) {
- rx = 0;
+ rx = 0f;
rxAuto = true;
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
@@ -126,8 +106,8 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
}
ctx.userAgent.displayError(be);
}
- if (rx > w / 2) {
- rx = w / 2;
+ if (rx > w / 2f) {
+ rx = w / 2f;
}
// 'ry' attribute - default is rx
@@ -143,8 +123,8 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
}
ctx.userAgent.displayError(be);
}
- if (ry > h / 2) {
- ry = h / 2;
+ if (ry > h / 2f) {
+ ry = h / 2f;
}
// Check whether rx was auto
@@ -158,10 +138,10 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
}
Shape shape;
- if (rx == 0 || ry == 0) {
+ if (rx == 0f || ry == 0f) {
shape = new Rectangle2D.Float(x, y, w, h);
} else {
- shape = new RoundRectangle2D.Float(x, y, w, h, rx * 2, ry * 2);
+ shape = new RoundRectangle2D.Float(x, y, w, h, rx * 2f, ry * 2f);
}
shapeNode.setShape(shape);
} catch (LiveAttributeException ex) {
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGShapeElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGShapeElementBridge.java
index 706239a5a..f117a23a2 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGShapeElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGShapeElementBridge.java
@@ -22,8 +22,10 @@
import org.w3c.dom.Element;
+import io.sf.carte.echosvg.anim.dom.AbstractSVGAnimatedLength;
import io.sf.carte.echosvg.css.engine.CSSEngineEvent;
import io.sf.carte.echosvg.css.engine.SVGCSSEngine;
+import io.sf.carte.echosvg.dom.svg.LiveAttributeException;
import io.sf.carte.echosvg.gvt.GraphicsNode;
import io.sf.carte.echosvg.gvt.ShapeNode;
import io.sf.carte.echosvg.gvt.ShapePainter;
@@ -129,6 +131,28 @@ protected ShapePainter createShapePainter(BridgeContext ctx, Element e, ShapeNod
*/
protected abstract void buildShape(BridgeContext ctx, Element e, ShapeNode node);
+ /**
+ * Give a safe value for an animated length, regardless of exceptions.
+ *
+ * @param animValue the animated length.
+ * @param defValue the default value.
+ * @return the value.
+ */
+ float safeAnimatedCheckedValue(AbstractSVGAnimatedLength animValue, float defValue) {
+ float value;
+ try {
+ value = animValue.getCheckedValue();
+ } catch (LiveAttributeException ex) {
+ value = defValue;
+ BridgeException be = new BridgeException(ctx, ex);
+ if (ctx.userAgent == null) {
+ throw be;
+ }
+ ctx.userAgent.displayError(be);
+ }
+ return value;
+ }
+
/**
* Returns false as shapes are not a container.
*/
diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGUseElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGUseElementBridge.java
index 669158b2d..dde565e02 100644
--- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGUseElementBridge.java
+++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGUseElementBridge.java
@@ -34,7 +34,6 @@
import io.sf.carte.echosvg.anim.dom.AbstractSVGAnimatedLength;
import io.sf.carte.echosvg.anim.dom.AnimatedLiveAttributeValue;
-import io.sf.carte.echosvg.anim.dom.SVGOMAnimatedLength;
import io.sf.carte.echosvg.anim.dom.SVGOMDocument;
import io.sf.carte.echosvg.anim.dom.SVGOMUseElement;
import io.sf.carte.echosvg.constants.XMLConstants;
@@ -173,11 +172,11 @@ public CompositeGraphicsNode buildCompositeGraphicsNode(BridgeContext ctx, Eleme
// on the 'use' element, then these values will override the
// corresponding attributes on the 'svg' in the generated tree.
try {
- SVGOMAnimatedLength al = (SVGOMAnimatedLength) ue.getWidth();
+ AbstractSVGAnimatedLength al = (AbstractSVGAnimatedLength) ue.getWidth();
if (al.isSpecified()) {
localRefElement.setAttributeNS(null, SVG_WIDTH_ATTRIBUTE, al.getAnimVal().getValueAsString());
}
- al = (SVGOMAnimatedLength) ue.getHeight();
+ al = (AbstractSVGAnimatedLength) ue.getHeight();
if (al.isSpecified()) {
localRefElement.setAttributeNS(null, SVG_HEIGHT_ATTRIBUTE, al.getAnimVal().getValueAsString());
}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/bridge/LoadPermissionsTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/bridge/LoadPermissionsTest.java
index f3d399f93..83ad7b347 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/bridge/LoadPermissionsTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/bridge/LoadPermissionsTest.java
@@ -111,14 +111,14 @@ public void testBridgeExceptionInvalidCSS() throws Exception {
}
@Test
- public void testBridgeExceptionEllipseMissingRx() throws Exception {
- runTest("application/java-archive", "bridge/error/ellipse-missing-rx", "ANY", false, false,
+ public void testBridgeExceptionEllipseWrongUnitRx() throws Exception {
+ runTest("text/javascript", "bridge/error/ellipse-wrong-unit-rx", "ANY", false, false,
"io.sf.carte.echosvg.bridge.BridgeException");
}
@Test
- public void testBridgeExceptionEllipseMissingRy() throws Exception {
- runTest("application/java-archive", "bridge/error/ellipse-missing-ry", "ANY", false, false,
+ public void testBridgeExceptionEllipseWrongUnitRy() throws Exception {
+ runTest("text/javascript", "bridge/error/ellipse-wrong-unit-ry", "ANY", false, false,
"io.sf.carte.echosvg.bridge.BridgeException");
}
diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec11RenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec11RenderingTest.java
index 62414e22d..6791b6d34 100644
--- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec11RenderingTest.java
+++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpec11RenderingTest.java
@@ -518,9 +518,14 @@ public void testRenderingResolutionPxMM() throws TranscoderException, IOExceptio
/*
* Shapes
*/
+ @Test
+ public void testShapesWrongAttr() throws TranscoderException, IOException {
+ testNVErrIgnore("samples/tests/spec/shapes/wrongAttr.svg", null, 10);
+ }
+
@Test
public void testShapesMissingAttr() throws TranscoderException, IOException {
- testNVErrIgnore("samples/tests/spec/shapes/missingAttr.svg", null, 5);
+ testNVErrIgnore("samples/tests/spec/shapes/missingAttr.svg", null, 1);
}
@Test
diff --git a/samples/tests/spec/shapes/wrongAttr.svg b/samples/tests/spec/shapes/wrongAttr.svg
new file mode 100644
index 000000000..ca91eb511
--- /dev/null
+++ b/samples/tests/spec/shapes/wrongAttr.svg
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test-references/samples/tests/spec/shapes/wrongAttr.png b/test-references/samples/tests/spec/shapes/wrongAttr.png
new file mode 100644
index 000000000..7c16eaf48
Binary files /dev/null and b/test-references/samples/tests/spec/shapes/wrongAttr.png differ
diff --git a/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-rx.svg b/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-rx.svg
similarity index 86%
rename from test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-rx.svg
rename to test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-rx.svg
index 03ded44e7..83b3130fb 100644
--- a/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-rx.svg
+++ b/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-rx.svg
@@ -32,12 +32,12 @@
diff --git a/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-ry.svg b/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-ry.svg
similarity index 86%
rename from test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-ry.svg
rename to test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-ry.svg
index 058d9c7ad..a9870dbd9 100644
--- a/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-missing-ry.svg
+++ b/test-resources/io/sf/carte/echosvg/bridge/error/ellipse-wrong-unit-ry.svg
@@ -32,12 +32,12 @@