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 @@ + + + + + + + + + + + + + + + + +Test wrong shape attributes + + + + + Test wrong shape attributes + Wrong attributes may disable the rendering of the element + + + + + + + + + + + + + <rect> + <circle> + <ellipse> + + + + + + + + + + + wrong width + wrong height + wrong w & h + + + + + + + + + wrong cx + wrong r + + + + + + + + + + wrong rx + wrong ry + wrong rx & ry + + + + + 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 @@ -Error: attribute "rx" is missing on <ellipse> +Error: wrong unit in attribute "rx" on <ellipse> - + @@ -45,15 +45,15 @@ - Error: attribute "rx" is missing on <ellipse> + Error: wrong unit in attribute "rx" on <ellipse> A green <ellipse> element - A red <ellipse> element without the "rx" attribute + A red <ellipse>element with wrong unit in the "rx" attribute - + 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 @@ -Error: attribute "ry" is missing on <ellipse> +Error: wrong unit in attribute "ry" on <ellipse> - + @@ -45,15 +45,15 @@ - Error: attribute "ry" is missing on <ellipse> + Error: wrong unit in attribute "ry" on <ellipse> A green <ellipse> element - A red <ellipse> element without the "ry" attribute + A red <ellipse>element with wrong unit in the "ry" attribute - +