Skip to content

Commit

Permalink
SVG2 compliance for viewBox attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosame committed Aug 6, 2024
1 parent 643dccc commit 77573ea
Show file tree
Hide file tree
Showing 18 changed files with 282 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ protected void reset() {
/**
* Initializes the length, if needed.
*/
protected void revalidate() {
protected void revalidate() throws LiveAttributeException {
if (valid) {
return;
}
Expand Down Expand Up @@ -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];
Expand All @@ -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;
}
Expand Down Expand Up @@ -376,6 +375,12 @@ public void setHeight(float height) throws DOMException {
reset();
}

@Override
public float[] toArray() throws LiveAttributeException {
revalidate();
return super.toArray();
}

}

/**
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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);

Expand Down Expand Up @@ -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 {
Expand All @@ -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 <width> or <height> is an error
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 77573ea

Please sign in to comment.