diff --git a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java index f6687063d..7a0e4258b 100644 --- a/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java +++ b/echosvg-anim/src/main/java/io/sf/carte/echosvg/anim/dom/SVGOMAnimatedRect.java @@ -204,7 +204,7 @@ protected void reset() { /** * Initializes the length, if needed. */ - protected void revalidate() { + protected void revalidate() throws LiveAttributeException { if (valid) { return; } @@ -245,20 +245,19 @@ public void calcValue(int line, int column) throws ParseException { try { p.parse(s); } catch (CalcParseException cpe) { - StyleValue value; ValueFactory factory = new ValueFactory(); try { - value = factory.parseProperty(s); + StyleValue value = factory.parseProperty(s); + if (!computeRectangle(value, numbers)) { + throw new LiveAttributeException(element, localName, + LiveAttributeException.ERR_ATTRIBUTE_MALFORMED, s); + } } catch (Exception e) { LiveAttributeException ex = new LiveAttributeException(element, localName, LiveAttributeException.ERR_ATTRIBUTE_MALFORMED, s); ex.initCause(e); throw ex; } - if (!computeRectangle(value, numbers)) { - throw new LiveAttributeException(element, localName, - LiveAttributeException.ERR_ATTRIBUTE_MALFORMED, s); - } } x = numbers[0]; y = numbers[1]; @@ -268,7 +267,7 @@ public void calcValue(int line, int column) throws ParseException { valid = true; } - private boolean computeRectangle(StyleValue value, float[] numbers) throws LiveAttributeException { + private boolean computeRectangle(StyleValue value, float[] numbers) throws DOMException { if (value.getCssValueType() != CssType.LIST) { return false; } @@ -376,6 +375,12 @@ public void setHeight(float height) throws DOMException { reset(); } + @Override + public float[] toArray() throws LiveAttributeException { + revalidate(); + return super.toArray(); + } + } /** @@ -469,6 +474,14 @@ protected void setAnimatedValue(float x, float y, float w, float h) { this.h = h; } + @Override + public float[] toArray() throws LiveAttributeException { + if (hasAnimVal) { + return super.toArray(); + } + return ((SVGOMRect) getBaseVal()).toArray(); + } + } static class CalcParseException extends ParseException { diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java index e44b93ab4..125bd59bb 100644 --- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java +++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/CursorManager.java @@ -459,8 +459,13 @@ protected Filter cursorHrefToFilter(Element cursorElement, ParsedURL purl, Point // Handle the viewBox transform AffineTransform at = ViewBox.getPreserveAspectRatioTransform(rootElement, cursorSize.width, cursorSize.height, ctx); - Filter filter = node.getGraphicsNodeRable(true); - f = new AffineRable8Bit(filter, at); + if (at == null) { + // disable the rendering of the element + return null; + } else { + Filter filter = node.getGraphicsNodeRable(true); + f = new AffineRable8Bit(filter, at); + } } catch (BridgeException ex) { throw ex; } catch (SecurityException ex) { @@ -493,6 +498,9 @@ protected Filter cursorHrefToFilter(Element cursorElement, ParsedURL purl, Point new float[] { 0, 0, preferredSize.width, preferredSize.height }, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN, true, cursorSize.width, cursorSize.height); + if (at == null) { + return null; + } } f = new AffineRable8Bit(filter, at); } else { diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGImageElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGImageElementBridge.java index 0614ad29e..317cf521a 100644 --- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGImageElementBridge.java +++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGImageElementBridge.java @@ -844,7 +844,12 @@ protected static void initializeViewport(BridgeContext ctx, Element e, GraphicsN _par.check(); AffineTransform at = ViewBox.getPreserveAspectRatioTransform(e, vb, w, h, _par, ctx); - at.preConcatenate(AffineTransform.getTranslateInstance(x, y)); + if (at == null) { + // disable the rendering of the element + return; + } else { + at.preConcatenate(AffineTransform.getTranslateInstance(x, y)); + } node.setTransform(at); // 'overflow' and 'clip' diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGPatternElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGPatternElementBridge.java index c83cea9f6..71a66ab73 100644 --- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGPatternElementBridge.java +++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGPatternElementBridge.java @@ -165,7 +165,12 @@ public Paint createPaint(BridgeContext ctx, Element patternElement, Element pain AffineTransform preserveAspectRatioTransform = ViewBox.getPreserveAspectRatioTransform(patternElement, viewBoxStr, aspectRatioStr, w, h, ctx); - patternContentTransform.concatenate(preserveAspectRatioTransform); + if (preserveAspectRatioTransform == null) { + // disable the rendering of the element + return null; + } else { + patternContentTransform.concatenate(preserveAspectRatioTransform); + } } else { // // Process patternContentUnitsTransform diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGSVGElementBridge.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGSVGElementBridge.java index fdcb8c9ce..88a6821af 100644 --- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGSVGElementBridge.java +++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/SVGSVGElementBridge.java @@ -148,9 +148,14 @@ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { float actualWidth = w; float actualHeight = h; try { - AffineTransform vtInv = viewingTransform.createInverse(); - actualWidth = (float) (w * vtInv.getScaleX()); - actualHeight = (float) (h * vtInv.getScaleY()); + if (viewingTransform == null) { + // disable the rendering of the element + return null; + } else { + AffineTransform vtInv = viewingTransform.createInverse(); + actualWidth = (float) (w * vtInv.getScaleX()); + actualHeight = (float) (h * vtInv.getScaleY()); + } } catch (NoninvertibleTransformException ex) { } @@ -231,8 +236,18 @@ public void setSize(double w, double h) { if (vb.isSpecified()) { SVGRect vbr = vb.getAnimVal(); - actualWidth = vbr.getWidth(); - actualHeight = vbr.getHeight(); + try { + // The next two lines call revalidate(), + // so we check for an exception. + actualWidth = vbr.getWidth(); + actualHeight = vbr.getHeight(); + } catch (RuntimeException ex) { + if (ctx.userAgent != null) { + ctx.userAgent.displayError(ex); + } else { + throw ex; + } + } } ctx.openViewport(e, new SVGSVGElementViewport(actualWidth, actualHeight)); return cgn; @@ -344,10 +359,12 @@ public void handleAnimatedAttributeChanged(AnimatedLiveAttributeValue alav) { AffineTransform newVT = ViewBox.getPreserveAspectRatioTransform(e, vb, par, w, h, ctx); AffineTransform oldVT = cgn.getViewingTransform(); - if ((newVT.getScaleX() != oldVT.getScaleX()) || (newVT.getScaleY() != oldVT.getScaleY()) - || (newVT.getShearX() != oldVT.getShearX()) || (newVT.getShearY() != oldVT.getShearY())) + if (newVT == null || (newVT.getScaleX() != oldVT.getScaleX()) + || (newVT.getScaleY() != oldVT.getScaleY()) + || (newVT.getShearX() != oldVT.getShearX()) + || (newVT.getShearY() != oldVT.getShearY())) { rebuild = true; - else { + } else { // Only differs in translate. cgn.setViewingTransform(newVT); diff --git a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java index a1bf8fb70..f61391f3d 100644 --- a/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java +++ b/echosvg-bridge/src/main/java/io/sf/carte/echosvg/bridge/ViewBox.java @@ -27,7 +27,6 @@ import org.w3c.dom.svg.SVGAnimatedPreserveAspectRatio; import org.w3c.dom.svg.SVGAnimatedRect; import org.w3c.dom.svg.SVGPreserveAspectRatio; -import org.w3c.dom.svg.SVGRect; import io.sf.carte.doc.style.css.CSSUnit; import io.sf.carte.doc.style.css.CSSValue.CssType; @@ -39,6 +38,7 @@ import io.sf.carte.doc.style.css.property.ValueList; import io.sf.carte.echosvg.anim.dom.SVGOMAnimatedRect; import io.sf.carte.echosvg.dom.svg.LiveAttributeException; +import io.sf.carte.echosvg.dom.svg.SVGOMRect; import io.sf.carte.echosvg.dom.util.DOMUtilities; import io.sf.carte.echosvg.parser.AWTTransformProducer; import io.sf.carte.echosvg.parser.FragmentIdentifierHandler; @@ -147,9 +147,10 @@ public static AffineTransform getViewTransform(String ref, Element e, float w, f // the additional transform that may appear on the URI AffineTransform transform = getPreserveAspectRatioTransform(vb, align, meet, w, h); - if (vh.hasTransform) { + if (transform != null && vh.hasTransform) { transform.concatenate(vh.getAffineTransform()); } + return transform; } @@ -193,7 +194,8 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, float w * @param h The height of the effective viewport * @param ctx The BridgeContext to use for error information */ - public static AffineTransform getPreserveAspectRatioTransform(Element e, float w, float h, BridgeContext ctx) { + public static AffineTransform getPreserveAspectRatioTransform(Element e, float w, float h, + BridgeContext ctx) throws BridgeException { String viewBox = e.getAttributeNS(null, SVG_VIEW_BOX_ATTRIBUTE); String aspectRatio = e.getAttributeNS(null, SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE); @@ -212,13 +214,23 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, float w * @param ctx The BridgeContext to use for error information */ public static AffineTransform getPreserveAspectRatioTransform(Element e, String viewBox, String aspectRatio, - float w, float h, BridgeContext ctx) { + float w, float h, BridgeContext ctx) throws BridgeException { // no viewBox specified if (viewBox.length() == 0) { return new AffineTransform(); } - float[] vb = parseViewBoxAttribute(e, viewBox, ctx); + float[] vb; + try { + vb = parseViewBoxAttribute(e, viewBox, ctx); + } catch (BridgeException be) { + if (ctx.userAgent != null) { + ctx.userAgent.displayError(be); + } else { + throw be; + } + return new AffineTransform(); + } // 'preserveAspectRatio' attribute PreserveAspectRatioParser p = new PreserveAspectRatioParser(); @@ -227,8 +239,14 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, String try { p.parse(aspectRatio); } catch (ParseException pEx) { - throw new BridgeException(ctx, e, pEx, ERR_ATTRIBUTE_VALUE_MALFORMED, + BridgeException be = new BridgeException(ctx, e, pEx, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] { SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE, aspectRatio, pEx }); + if (ctx.userAgent != null) { + ctx.userAgent.displayError(be); + } else { + throw be; + } + return new AffineTransform(); } return getPreserveAspectRatioTransform(vb, ph.align, ph.meet, w, h); @@ -245,7 +263,7 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, String * @param ctx The BridgeContext to use for error information */ public static AffineTransform getPreserveAspectRatioTransform(Element e, float[] vb, float w, float h, - BridgeContext ctx) { + BridgeContext ctx) throws BridgeException { String aspectRatio = e.getAttributeNS(null, SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE); @@ -275,7 +293,7 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, float[] * @param ctx The BridgeContext to use for error information */ public static AffineTransform getPreserveAspectRatioTransform(Element e, float[] vb, float w, float h, - SVGAnimatedPreserveAspectRatio aPAR, BridgeContext ctx) { + SVGAnimatedPreserveAspectRatio aPAR, BridgeContext ctx) throws BridgeException { // 'preserveAspectRatio' attribute try { @@ -300,37 +318,68 @@ public static AffineTransform getPreserveAspectRatioTransform(Element e, float[] * @param ctx the BridgeContext to use for error information */ public static AffineTransform getPreserveAspectRatioTransform(Element e, SVGAnimatedRect aViewBox, - SVGAnimatedPreserveAspectRatio aPAR, float w, float h, BridgeContext ctx) { - - if (!((SVGOMAnimatedRect) aViewBox).isSpecified()) { + SVGAnimatedPreserveAspectRatio aPAR, float w, float h, BridgeContext ctx) + throws BridgeException { + SVGOMAnimatedRect rectVB = (SVGOMAnimatedRect) aViewBox; + if (!rectVB.isSpecified()) { // no viewBox specified return new AffineTransform(); } - SVGRect viewBox = aViewBox.getAnimVal(); - float[] vb = { viewBox.getX(), viewBox.getY(), viewBox.getWidth(), viewBox.getHeight() }; - return getPreserveAspectRatioTransform(e, vb, w, h, aPAR, ctx); + float[] vb; + try { + vb = ((SVGOMRect) rectVB.getAnimVal()).toArray(); + } catch (LiveAttributeException ex) { + if (ctx.userAgent != null) { + ctx.userAgent.displayError(ex); + } else { + throw new BridgeException(ctx, ex); + } + return new AffineTransform(); + } + + AffineTransform art; + try { + art = getPreserveAspectRatioTransform(e, vb, w, h, aPAR, ctx); + } catch (BridgeException ex) { + if (ctx.userAgent != null) { + ctx.userAgent.displayError(ex); + } else { + throw ex; + } + art = new AffineTransform(); + } + return art; } /** * Parses a viewBox attribute. * * @param e the element whose viewBox attribute value is being parsed - * @param value the viewBox + * @param value the viewBox, cannot be null nor empty. * @param ctx the BridgeContext to use for error information * @return The 4 viewbox components or null. */ - public static float[] parseViewBoxAttribute(Element e, String value, BridgeContext ctx) { - if (value.length() == 0) { + public static float[] parseViewBoxAttribute(Element e, String value, BridgeContext ctx) + throws BridgeException { + if (value.isEmpty()) { + /* + * Cannot return anything meaningful, so return null + */ return null; } float[] vb = new float[4]; ValueFactory factory = new ValueFactory(); - StyleValue sv = factory.parseProperty(value); - if (!computeRectangle(sv, vb)) { - throw new BridgeException(ctx, e, ERR_ATTRIBUTE_VALUE_MALFORMED, - new Object[] { SVG_VIEW_BOX_ATTRIBUTE, value }); + try { + StyleValue sv = factory.parseProperty(value); + if (!computeRectangle(sv, vb)) { + throw new BridgeException(ctx, e, ERR_ATTRIBUTE_VALUE_MALFORMED, + new Object[] { SVG_VIEW_BOX_ATTRIBUTE, value }); + } + } catch (Exception ex) { + throw new BridgeException(ctx, e, ex, ERR_ATTRIBUTE_VALUE_MALFORMED, + new Object[] { SVG_VIEW_BOX_ATTRIBUTE, value, ex }); } // A negative value for or is an error @@ -341,7 +390,7 @@ public static float[] parseViewBoxAttribute(Element e, String value, BridgeConte // A value of zero for width or height disables rendering of the element if (vb[2] == 0 || vb[3] == 0) { - return null; // FIXME : must disable ! + return null; // disable rendering } return vb; @@ -397,7 +446,7 @@ static boolean computeRectangle(StyleValue value, float[] numbers) throws DOMExc public static AffineTransform getPreserveAspectRatioTransform(float[] vb, short align, boolean meet, float w, float h) { if (vb == null) { - return new AffineTransform(); + return null; } AffineTransform result = new AffineTransform(); diff --git a/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGOMRect.java b/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGOMRect.java index 62afa8434..a599d3bc6 100644 --- a/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGOMRect.java +++ b/echosvg-svg-dom/src/main/java/io/sf/carte/echosvg/dom/svg/SVGOMRect.java @@ -25,8 +25,10 @@ * An implementation of {@link SVGRect} that is not associated with an * attribute. * - * @author Thomas DeWeese - * @author For later modifications, see Git history. + *

+ * Original author: Thomas DeWeese. + * For later modifications, see Git history. + *

* @version $Id$ */ public class SVGOMRect implements SVGRect { @@ -131,4 +133,16 @@ public void setHeight(float height) throws DOMException { this.h = height; } + /** + * Convert this rectangle to an array of {@code x}, {@code y}, {@code width} and + * {@code height} values. + * + * @return the array of values. + * @throws LiveAttributeException if one or more of the values are wrong. + */ + public float[] toArray() throws LiveAttributeException { + float[] a = { x, y, w, h }; + return a; + } + } diff --git a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/JSVGScrollPane.java b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/JSVGScrollPane.java index a5690d875..e949044fb 100644 --- a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/JSVGScrollPane.java +++ b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/JSVGScrollPane.java @@ -622,7 +622,13 @@ protected Rectangle2D getViewBoxRect() { String viewBoxStr = el.getAttributeNS(null, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE).trim(); if (viewBoxStr.length() != 0) { float[] rect = ViewBox.parseViewBoxAttribute(el, viewBoxStr, null); - return new Rectangle2D.Float(rect[0], rect[1], rect[2], rect[3]); + Rectangle2D rect2d; + if (rect != null) { + rect2d = new Rectangle2D.Float(rect[0], rect[1], rect[2], rect[3]); + } else { + rect2d = new Rectangle2D.Float(0f, 0f, 0f, 0f); + } + return rect2d; } GraphicsNode gn = canvas.getGraphicsNode(); if (gn == null) diff --git a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java index 9a73e695d..6732d549d 100644 --- a/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java +++ b/echosvg-swing/src/main/java/io/sf/carte/echosvg/swing/svg/JSVGComponent.java @@ -40,6 +40,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import javax.swing.JOptionPane; @@ -833,7 +834,7 @@ public void setGraphicsNode(GraphicsNode gn, boolean createDispatcher) { prevComponentSize = getSize(); AffineTransform at = calculateViewingTransform(fragmentIdentifier, elt); CanvasGraphicsNode cgn = getCanvasGraphicsNode(gn); - if (cgn != null) { + if (cgn != null && at != null) { cgn.setViewingTransform(at); } viewingTransform = null; @@ -982,7 +983,7 @@ protected boolean updateRenderingTransform() { d.height = 1; final AffineTransform at = calculateViewingTransform(fragmentIdentifier, elt); AffineTransform vt = getViewingTransform(); - if (at.equals(vt)) { + if (Objects.equals(vt, at)) { // No new transform // Only repaint if size really changed. return ((oldD.width != d.width) || (oldD.height != d.height)); diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/anim/dom/test/SVGOMAnimatedRectTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/anim/dom/test/SVGOMAnimatedRectTest.java index 27bcee4d3..8fcb74808 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/anim/dom/test/SVGOMAnimatedRectTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/anim/dom/test/SVGOMAnimatedRectTest.java @@ -150,6 +150,14 @@ public void testCalcMixedCase() { assertEquals(450f, rect.getHeight(), TOL); } + @Test + public void testCalcValueUnitError() throws LiveAttributeException { + SVGOMAnimatedRect animRect = createAnimatedRect("0 0 calc(10mm) 500"); + SVGRect rect = animRect.getBaseVal(); + + assertThrows(LiveAttributeException.class, () -> rect.getX()); + } + private SVGOMAnimatedRect createAnimatedRect(String attrValue) { element.setAttributeNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE, attrValue); diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java index 5aa91157f..6aa902703 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/AbstractSamplesRendering.java @@ -36,6 +36,8 @@ */ public class AbstractSamplesRendering { + static final String BROWSER_MEDIA = "screen"; + /** * To test the tEXt chunk. */ diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesCanvgRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesCanvgRenderingTest.java index 779c19c45..3f3dfb632 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesCanvgRenderingTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesCanvgRenderingTest.java @@ -41,8 +41,6 @@ */ public class SamplesCanvgRenderingTest extends AbstractSamplesRendering { - private static final String BROWSER_MEDIA = "screen"; - @BeforeAll public static void setUpBeforeClass() throws Exception { TestFonts.loadTestFonts(); diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java index 74418698d..31dbd5cf0 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesSpecRenderingTest.java @@ -496,6 +496,11 @@ public void testPaintsRadialGradientOrientation() throws TranscoderException, IO /* * Rendering */ + @Test + public void testRenderingInvalidViewbox() throws TranscoderException, IOException { + testErrIgnore("samples/tests/spec/rendering/invalidViewbox.svg", BROWSER_MEDIA, 3, true); + } + @Test public void testRenderingOpacity() throws TranscoderException, IOException { test("samples/tests/spec/rendering/opacity.svg"); @@ -515,6 +520,11 @@ public void testRenderingResolutionPxMM() throws TranscoderException, IOExceptio testResolutionPxMM("samples/tests/spec/rendering/resolution.svg", 0.25f); } + @Test + public void testRenderingZeroWidthViewbox() throws TranscoderException, IOException { + test("samples/tests/spec/rendering/zeroWidthViewbox.svg"); + } + /* * Shapes */ diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java index 39c3e39a3..e3a3166ab 100644 --- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java +++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/SVGAbstractTranscoder.java @@ -312,6 +312,10 @@ protected void transcode(Document document, String uri, TranscoderOutput output) } else if (!viewBox.isEmpty()) { String aspectRatio = root.getAttributeNS(null, SVGConstants.SVG_PRESERVE_ASPECT_RATIO_ATTRIBUTE); Px = ViewBox.getPreserveAspectRatioTransform(root, viewBox, aspectRatio, width, height, ctx); + // check for null, which means zero width or height + if (Px == null) { + Px = AffineTransform.getTranslateInstance(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + } } else { // no viewBox has been specified, create a scale transform float xscale, yscale; diff --git a/samples/tests/spec/rendering/invalidViewbox.svg b/samples/tests/spec/rendering/invalidViewbox.svg new file mode 100644 index 000000000..5e1e36e82 --- /dev/null +++ b/samples/tests/spec/rendering/invalidViewbox.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + diff --git a/samples/tests/spec/rendering/zeroWidthViewbox.svg b/samples/tests/spec/rendering/zeroWidthViewbox.svg new file mode 100644 index 000000000..e9db82e0b --- /dev/null +++ b/samples/tests/spec/rendering/zeroWidthViewbox.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + diff --git a/test-references/samples/tests/spec/rendering/invalidViewbox.png b/test-references/samples/tests/spec/rendering/invalidViewbox.png new file mode 100644 index 000000000..318dbfb57 Binary files /dev/null and b/test-references/samples/tests/spec/rendering/invalidViewbox.png differ diff --git a/test-references/samples/tests/spec/rendering/zeroWidthViewbox.png b/test-references/samples/tests/spec/rendering/zeroWidthViewbox.png new file mode 100644 index 000000000..011c5dcb6 Binary files /dev/null and b/test-references/samples/tests/spec/rendering/zeroWidthViewbox.png differ