Skip to content

Commit

Permalink
anim,bridge: continue rendering if x/y/width/height attributes of lin…
Browse files Browse the repository at this point in the history
…e,image,svg,use are wrong [SVG2]

See #113.
  • Loading branch information
carlosame committed Aug 14, 2024
1 parent 3a7fb4a commit a31c966
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,23 @@ public AbstractSVGAnimatedLength(AbstractElement elt, String ns, String ln, shor
*/
protected abstract String getDefaultValue();

/**
* The evaluation of the value has failed, get the default.
*
* @return the default value.
*/
public float getDefault() {
AnimSVGLength length = new AnimSVGLength(direction);
length.parse(getDefaultValue());
try {
return UnitProcessor.svgToUserSpace(length.value, length.unitType, direction,
length.context);
} catch (IllegalArgumentException ex) {
// Only if the default is broken
return 0f;
}
}

/**
* <b>DOM</b>: Implements {@link SVGAnimatedLength#getBaseVal()}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.w3c.dom.svg.SVGFitToViewBox;
import org.w3c.dom.svg.SVGTransformable;

import io.sf.carte.echosvg.anim.dom.AbstractSVGAnimatedLength;
import io.sf.carte.echosvg.anim.dom.AnimatedLiveAttributeValue;
import io.sf.carte.echosvg.anim.dom.SVGOMAnimatedTransformList;
import io.sf.carte.echosvg.anim.dom.SVGOMElement;
Expand Down Expand Up @@ -66,8 +67,10 @@
* <li>visibility</li>
* </ul>
*
* @author <a href="mailto:[email protected]">Thierry Kormann</a>
* @author For later modifications, see Git history.
* <p>
* Original author: <a href="mailto:[email protected]">Thierry Kormann</a>.
* For later modifications, see Git history.
* </p>
* @version $Id$
*/
public abstract class AbstractGraphicsNodeBridge extends AnimatableSVGBridge
Expand Down Expand Up @@ -150,6 +153,49 @@ public void buildGraphicsNode(BridgeContext ctx, Element e, GraphicsNode node) {
initializeDynamicSupport(ctx, e, node);
}

/**
* Give a safe value for an animated length, regardless of exceptions.
*
* @param animValue the animated length.
* @return the value.
*/
float safeAnimatedLength(AbstractSVGAnimatedLength animValue) throws BridgeException {
float value;
try {
value = animValue.getCheckedValue();
} catch (LiveAttributeException ex) {
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
value = animValue.getDefault();
}
return value;
}

/**
* 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 safeAnimatedLength(AbstractSVGAnimatedLength animValue, float defValue) throws BridgeException {
float value;
try {
value = animValue.getCheckedValue();
} catch (LiveAttributeException ex) {
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
value = defValue;
}
return value;
}

/**
* Returns true if the graphics node has to be displayed, false otherwise.
*/
Expand All @@ -162,7 +208,8 @@ public boolean getDisplay(Element e) {
* Returns an {@link AffineTransform} that is the transformation to be applied
* to the node.
*/
protected AffineTransform computeTransform(SVGTransformable te, BridgeContext ctx) {
protected AffineTransform computeTransform(SVGTransformable te, BridgeContext ctx)
throws BridgeException {
try {
AffineTransform at = new AffineTransform();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
/**
* Bridge class for the &lt;circle&gt; element.
*
* @author <a href="mailto:[email protected]">Thierry Kormann</a>
* @author For later modifications, see Git history.
* <p>
* Original author: <a href="mailto:[email protected]">Thierry Kormann</a>.
* For later modifications, see Git history.
* </p>
* @version $Id$
*/
public class SVGCircleElementBridge extends SVGShapeElementBridge {
Expand Down Expand Up @@ -75,15 +77,15 @@ protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {

// 'cx' attribute - default is 0
AbstractSVGAnimatedLength _cx = (AbstractSVGAnimatedLength) ce.getCx();
float cx = safeAnimatedCheckedValue(_cx, 0f);
float cx = safeAnimatedLength(_cx, 0f);

// 'cy' attribute - default is 0
AbstractSVGAnimatedLength _cy = (AbstractSVGAnimatedLength) ce.getCy();
float cy = safeAnimatedCheckedValue(_cy, 0f);
float cy = safeAnimatedLength(_cy, 0f);

// 'r' attribute - default is 0 (SVG2)
AbstractSVGAnimatedLength _r = (AbstractSVGAnimatedLength) ce.getR();
float r = safeAnimatedCheckedValue(_r, 0f);
float r = safeAnimatedLength(_r, 0f);

float x = cx - r;
float y = cy - r;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
/**
* Bridge class for the &lt;ellipse&gt; element.
*
* @author <a href="mailto:[email protected]">Thierry Kormann</a>
* @author For later modifications, see Git history.
* <p>
* Original author: <a href="mailto:[email protected]">Thierry Kormann</a>.
* For later modifications, see Git history.
* </p>
* @version $Id$
*/
public class SVGEllipseElementBridge extends SVGShapeElementBridge {
Expand Down Expand Up @@ -69,58 +71,59 @@ public Bridge getInstance() {
* @param shapeNode the shape node to initialize
*/
@Override
protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode)
throws BridgeException {
SVGOMEllipseElement ee = (SVGOMEllipseElement) e;

// 'cx' attribute - default is 0
AbstractSVGAnimatedLength _cx = (AbstractSVGAnimatedLength) ee.getCx();
float cx = safeAnimatedLength(_cx, 0f);

// 'cy' attribute - default is 0
AbstractSVGAnimatedLength _cy = (AbstractSVGAnimatedLength) ee.getCy();
float cy = safeAnimatedLength(_cy, 0f);

// 'rx' attribute - default is auto (SVG2)
boolean rxAuto = false;
AbstractSVGAnimatedLength _rx = (AbstractSVGAnimatedLength) ee.getRx();
float rx;
try {
SVGOMEllipseElement ee = (SVGOMEllipseElement) e;

// 'cx' attribute - default is 0
AbstractSVGAnimatedLength _cx = (AbstractSVGAnimatedLength) ee.getCx();
float cx = safeAnimatedCheckedValue(_cx, 0f);

// 'cy' attribute - default is 0
AbstractSVGAnimatedLength _cy = (AbstractSVGAnimatedLength) ee.getCy();
float cy = safeAnimatedCheckedValue(_cy, 0f);

// 'rx' attribute - default is auto (SVG2)
boolean rxAuto = false;
AbstractSVGAnimatedLength _rx = (AbstractSVGAnimatedLength) ee.getRx();
float rx;
try {
rx = _rx.getCheckedValue();
} catch (LiveAttributeException ex) {
rx = 0f;
rxAuto = true;
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
rx = _rx.getCheckedValue();
} catch (LiveAttributeException ex) {
rx = 0f;
rxAuto = true;
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
}

// 'ry' attribute - default is auto (SVG2)
AbstractSVGAnimatedLength _ry = (AbstractSVGAnimatedLength) ee.getRy();
float ry;
try {
ry = _ry.getCheckedValue();
} catch (LiveAttributeException ex) {
ry = rx;
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
// 'ry' attribute - default is auto (SVG2)
AbstractSVGAnimatedLength _ry = (AbstractSVGAnimatedLength) ee.getRy();
float ry;
try {
ry = _ry.getCheckedValue();
} catch (LiveAttributeException ex) {
ry = rx;
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
}

// Check whether rx was auto
/*
* SVG2 §7.4: "When the computed value of ‘rx’ is auto, the used radius is equal
* to the absolute length used for ry, creating a circular arc. If both ‘rx’ and
* ‘ry’ have a computed value of auto, the used value is 0."
*/
if (rxAuto) {
rx = ry;
}
// Check whether rx was auto
/*
* SVG2 §7.4: "When the computed value of ‘rx’ is auto, the used radius is equal
* to the absolute length used for ry, creating a circular arc. If both ‘rx’ and
* ‘ry’ have a computed value of auto, the used value is 0."
*/
if (rxAuto) {
rx = ry;
}

try {
shapeNode.setShape(new Ellipse2D.Float(cx - rx, cy - ry, rx * 2f, ry * 2f));
} catch (LiveAttributeException ex) {
throw new BridgeException(ctx, ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@
/**
* Bridge class for the &lt;image&gt; element.
*
* @author <a href="mailto:[email protected]">Thierry Kormann</a>
* @author For later modifications, see Git history.
* <p>
* Original author: <a href="mailto:[email protected]">Thierry Kormann</a>.
* For later modifications, see Git history.
* </p>
* @version $Id$
*/
public class SVGImageElementBridge extends AbstractGraphicsNodeBridge {
Expand Down Expand Up @@ -481,7 +483,7 @@ protected void initializeDynamicSupport(BridgeContext ctx, Element e, GraphicsNo
* Invoked when the animated value of an animatable attribute has changed.
*/
@Override
public void handleAnimatedAttributeChanged(AnimatedLiveAttributeValue alav) {
public void handleAnimatedAttributeChanged(AnimatedLiveAttributeValue alav) throws BridgeException {
try {
String ns = alav.getNamespaceURI();
String ln = alav.getLocalName();
Expand Down Expand Up @@ -921,18 +923,19 @@ protected static ICCColorSpaceWithIntent extractColorSpace(Element element, Brid
* @param ctx the bridge context
* @param element the image element
*/
protected static Rectangle2D getImageBounds(BridgeContext ctx, Element element) {
try {
SVGImageElement ie = (SVGImageElement) element;
protected static Rectangle2D getImageBounds(BridgeContext ctx, Element element)
throws BridgeException {
SVGImageElement ie = (SVGImageElement) element;

// 'x' attribute - default is 0
AbstractSVGAnimatedLength _x = (AbstractSVGAnimatedLength) ie.getX();
float x = _x.getCheckedValue();
// 'x' attribute - default is 0
AbstractSVGAnimatedLength _x = (AbstractSVGAnimatedLength) ie.getX();
float x = safeLength(_x, ctx);

// 'y' attribute - default is 0
AbstractSVGAnimatedLength _y = (AbstractSVGAnimatedLength) ie.getY();
float y = _y.getCheckedValue();
// 'y' attribute - default is 0
AbstractSVGAnimatedLength _y = (AbstractSVGAnimatedLength) ie.getY();
float y = safeLength(_y, ctx);

try {
// 'width' attribute - required
AbstractSVGAnimatedLength _width = (AbstractSVGAnimatedLength) ie.getWidth();
float w = _width.getCheckedValue();
Expand All @@ -947,6 +950,29 @@ protected static Rectangle2D getImageBounds(BridgeContext ctx, Element element)
}
}

/**
* Give a safe value for an animated length, regardless of exceptions.
*
* @param animValue the animated length.
* @param defValue the default value.
* @return the value.
*/
private static float safeLength(AbstractSVGAnimatedLength animValue, BridgeContext ctx)
throws BridgeException {
float value;
try {
value = animValue.getCheckedValue();
} catch (LiveAttributeException ex) {
BridgeException be = new BridgeException(ctx, ex);
if (ctx.userAgent == null) {
throw be;
}
ctx.userAgent.displayError(be);
value = 0f;
}
return value;
}

GraphicsNode createBrokenImageNode(BridgeContext ctx, Element e, String uri, String message) {
SVGDocument doc = ctx.getUserAgent().getBrokenLinkDocument(e, uri,
Messages.formatMessage(URI_IMAGE_ERROR, new Object[] { message }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
/**
* Bridge class for the &lt;line&gt; element.
*
* @author <a href="mailto:[email protected]">Thierry Kormann</a>
* @author For later modifications, see Git history.
* <p>
* Original author: <a href="mailto:[email protected]">Thierry Kormann</a>.
* For later modifications, see Git history.
* </p>
* @version $Id$
*/
public class SVGLineElementBridge extends SVGDecoratedShapeElementBridge {
Expand Down Expand Up @@ -92,27 +94,27 @@ protected ShapePainter createFillStrokePainter(BridgeContext ctx, Element e, Sha
* @param shapeNode the shape node to initialize
*/
@Override
protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode) {
protected void buildShape(BridgeContext ctx, Element e, ShapeNode shapeNode)
throws BridgeException {
SVGOMLineElement le = (SVGOMLineElement) e;

try {
SVGOMLineElement le = (SVGOMLineElement) e;

// 'x1' attribute - default is 0
AbstractSVGAnimatedLength _x1 = (AbstractSVGAnimatedLength) le.getX1();
float x1 = _x1.getCheckedValue();
// 'x1' attribute - default is 0
AbstractSVGAnimatedLength _x1 = (AbstractSVGAnimatedLength) le.getX1();
float x1 = safeAnimatedLength(_x1, 0f);

// 'y1' attribute - default is 0
AbstractSVGAnimatedLength _y1 = (AbstractSVGAnimatedLength) le.getY1();
float y1 = _y1.getCheckedValue();
// 'y1' attribute - default is 0
AbstractSVGAnimatedLength _y1 = (AbstractSVGAnimatedLength) le.getY1();
float y1 = safeAnimatedLength(_y1, 0f);

// 'x2' attribute - default is 0
AbstractSVGAnimatedLength _x2 = (AbstractSVGAnimatedLength) le.getX2();
float x2 = _x2.getCheckedValue();
// 'x2' attribute - default is 0
AbstractSVGAnimatedLength _x2 = (AbstractSVGAnimatedLength) le.getX2();
float x2 = safeAnimatedLength(_x2, 0f);

// 'y2' attribute - default is 0
AbstractSVGAnimatedLength _y2 = (AbstractSVGAnimatedLength) le.getY2();
float y2 = _y2.getCheckedValue();
// 'y2' attribute - default is 0
AbstractSVGAnimatedLength _y2 = (AbstractSVGAnimatedLength) le.getY2();
float y2 = safeAnimatedLength(_y2, 0f);

try {
shapeNode.setShape(new Line2D.Float(x1, y1, x2, y2));
} catch (LiveAttributeException ex) {
throw new BridgeException(ctx, ex);
Expand Down
Loading

0 comments on commit a31c966

Please sign in to comment.