diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ParameterizedRenderingAccuracyTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ParameterizedRenderingAccuracyTest.java index 905c33335..b5ba4b52b 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ParameterizedRenderingAccuracyTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/ParameterizedRenderingAccuracyTest.java @@ -64,33 +64,36 @@ public void runTest(String uri, String parameter) throws MalformedURLException { /** * Gives a chance to the subclass to control the construction of the reference * PNG file from the svgFile name The refImgURL is built as: getRefImagePrefix() - * + svgDir + getRefImageSuffix() + svgFile + * + svgDir + getRefImageSuffix() + svgFile + parameter + getImageSuffix() + + * PNG_EXTENSION */ @Override protected String buildRefImgURL(String svgDir, String svgFile) { - return getRefImagePrefix() + svgDir + getRefImageSuffix() + svgFile + parameter + PNG_EXTENSION; + return getRefImagePrefix() + svgDir + getRefImageSuffix() + svgFile + parameter + getImageSuffix() + + PNG_EXTENSION; } /** * Gives a chance to the subclass to control the construction of the variation * URL, which is built as: getVariationPrefix() + svgDir + getVariationSuffix() - * + svgFile + parameter + PNG_EXTENSION + * + svgFile + parameter + getImageSuffix() + PNG_EXTENSION */ @Override public String[] buildVariationURLs(String svgDir, String svgFile) { String[] platforms = getVariationPlatforms(); String[] urls = new String[platforms.length + 1]; - urls[0] = getVariationPrefix() + svgDir + getVariationSuffix() + svgFile + parameter + PNG_EXTENSION; + urls[0] = getVariationPrefix() + svgDir + getVariationSuffix() + svgFile + parameter + getImageSuffix() + + PNG_EXTENSION; for (int i = 0; i < platforms.length; i++) { - urls[i + 1] = getVariationPrefix() + svgDir + getVariationSuffix() + svgFile + parameter + '_' - + platforms[i] + PNG_EXTENSION; + urls[i + 1] = getVariationPrefix() + svgDir + getVariationSuffix() + svgFile + parameter + getImageSuffix() + + '_' + platforms[i] + PNG_EXTENSION; } return urls; } @Override protected String buildSaveVariationPath(String svgDir, String svgFile) { - return getSaveVariationPrefix() + svgDir + getSaveVariationSuffix() + svgFile + parameter; + return getSaveVariationPrefix() + svgDir + getSaveVariationSuffix() + svgFile + parameter + getImageSuffix(); } /** @@ -101,7 +104,7 @@ protected String buildSaveVariationPath(String svgDir, String svgFile) { @Override public String buildCandidateReferenceFile(String svgDir, String svgFile) { return getCandidateReferencePrefix() + svgDir + getCandidateReferenceSuffix() + svgFile + parameter - + PNG_EXTENSION; + + getImageSuffix() + PNG_EXTENSION; } } diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/PreconfiguredRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/PreconfiguredRenderingTest.java index 90ff5f897..579f238c1 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/PreconfiguredRenderingTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/PreconfiguredRenderingTest.java @@ -37,6 +37,8 @@ public abstract class PreconfiguredRenderingTest extends SVGRenderingAccuracyTes public static final String SVG_EXTENSION = ".svg"; public static final String SVGZ_EXTENSION = ".svgz"; + private static final String HTML_EXTENSION = ".html"; + private static final String XHTML_EXTENSION = ".xhtml"; public static final char PATH_SEPARATOR = '/'; @@ -175,6 +177,10 @@ protected String[] breakSVGFile(String svgFile) { ret[2] = SVG_EXTENSION; } else if (svgFile.endsWith(SVGZ_EXTENSION)) { ret[2] = SVGZ_EXTENSION; + } else if (svgFile.endsWith(HTML_EXTENSION)) { + ret[2] = HTML_EXTENSION; + } else if (svgFile.endsWith(XHTML_EXTENSION)) { + ret[2] = XHTML_EXTENSION; } else { throw new IllegalArgumentException(svgFile); } diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesRenderingTest.java index 2cfc60a31..3c48edc1d 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesRenderingTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/SamplesRenderingTest.java @@ -929,6 +929,11 @@ public void testStyleElement() throws TranscoderException, IOException { test("samples/tests/spec/styling/styleElement.svg"); } + @Test + public void testXHTMLEmbed() throws TranscoderException, IOException { + testXHTML("samples/tests/spec/styling/css2.xhtml"); + } + /* * Text */ @@ -1521,6 +1526,24 @@ private void test(String file, boolean validating) throws TranscoderException, I runner.runTest(0.00001f, 0.00001f); } + /** + * Test the rendering of a SVG image inside an XHTML document. + * + *
+ * A small percentage of different pixels is allowed during the comparison to a + * reference image. + *
+ * + * @param file the HTML file to test. + * @throws TranscoderException + * @throws IOException + */ + private void testXHTML(String file) throws TranscoderException, IOException { + RenderingTest runner = new XHTMLRenderingAccuracyTest(); + runner.setFile(file); + runner.runTest(0.000001f, 0.000001f); + } + /** * Dynamic test of the rendering of a SVG file. * diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java index 5b951959f..90441331d 100644 --- a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/StyleBypassRenderingTest.java @@ -1437,9 +1437,6 @@ private void test(String file, String medium, boolean darkMode, boolean validati private class BypassRenderingTest extends RenderingTest { - private static final String HTML_EXTENSION = ".html"; - private static final String XHTML_EXTENSION = ".xhtml"; - private final String medium; /** @@ -1488,43 +1485,6 @@ protected void encode(URL srcURL, FileOutputStream fos) throws TranscoderExcepti helper.transcode(re, uri, dst, null); } - @Override - protected String[] breakSVGFile(String svgFile) { - if (svgFile == null) { - throw new IllegalArgumentException(svgFile); - } - - String[] ret = new String[3]; - - if (svgFile.endsWith(SVG_EXTENSION)) { - ret[2] = SVG_EXTENSION; - } else if (svgFile.endsWith(SVGZ_EXTENSION)) { - ret[2] = SVGZ_EXTENSION; - } else if (svgFile.endsWith(HTML_EXTENSION)) { - ret[2] = HTML_EXTENSION; - } else if (svgFile.endsWith(XHTML_EXTENSION)) { - ret[2] = XHTML_EXTENSION; - } else { - throw new IllegalArgumentException(svgFile); - } - - svgFile = svgFile.substring(0, svgFile.length() - ret[2].length()); - - int fileNameStart = svgFile.lastIndexOf(PATH_SEPARATOR); - String svgDir = ""; - if (fileNameStart != -1) { - if (svgFile.length() < fileNameStart + 2) { - // Nothing after PATH_SEPARATOR - throw new IllegalArgumentException(svgFile); - } - svgDir = svgFile.substring(0, fileNameStart + 1); - svgFile = svgFile.substring(fileNameStart + 1); - } - ret[0] = svgDir; - ret[1] = svgFile; - return ret; - } - protected String getImageSuffix() { if (!DEFAULT_MEDIUM.equals(medium)) { return '-' + medium + getDarkModeSuffix(); diff --git a/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/XHTMLRenderingAccuracyTest.java b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/XHTMLRenderingAccuracyTest.java new file mode 100644 index 000000000..13deec84a --- /dev/null +++ b/echosvg-test/src/test/java/io/sf/carte/echosvg/test/svg/XHTMLRenderingAccuracyTest.java @@ -0,0 +1,49 @@ +/* + + See the NOTICE file distributed with this work for additional + information regarding copyright ownership. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package io.sf.carte.echosvg.test.svg; + +import io.sf.carte.echosvg.transcoder.XMLAbstractTranscoder; +import io.sf.carte.echosvg.transcoder.image.ImageTranscoder; + +/** + * Checks for regressions in rendering of SVG inside an XHTML document. + * + * @author See Git history. + * @version $Id$ + */ +public class XHTMLRenderingAccuracyTest extends RenderingTest { + + public XHTMLRenderingAccuracyTest() { + super(); + setValidating(false); + } + + /** + * Returns theImageTranscoder
the Test should use
+ */
+ @Override
+ ImageTranscoder getTestImageTranscoder() {
+ ImageTranscoder t = super.getTestImageTranscoder();
+ t.addTranscodingHint(XMLAbstractTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
+ "http://www.w3.org/1999/xhtml");
+ t.addTranscodingHint(XMLAbstractTranscoder.KEY_DOCUMENT_ELEMENT, "html");
+ return t;
+ }
+
+}
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 9ccdf4ce9..b58c71f2b 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
@@ -26,11 +26,17 @@
import java.util.Collections;
import java.util.List;
+import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGSVGElement;
import io.sf.carte.echosvg.anim.dom.SAXSVGDocumentFactory;
+import io.sf.carte.echosvg.anim.dom.SVG12DOMImplementation;
import io.sf.carte.echosvg.anim.dom.SVGDOMImplementation;
import io.sf.carte.echosvg.anim.dom.SVGOMDocument;
import io.sf.carte.echosvg.bridge.BaseScriptingEnvironment;
@@ -48,7 +54,6 @@
import io.sf.carte.echosvg.bridge.UserAgentAdapter;
import io.sf.carte.echosvg.bridge.ViewBox;
import io.sf.carte.echosvg.bridge.svg12.SVG12BridgeContext;
-import io.sf.carte.echosvg.dom.util.DOMUtilities;
import io.sf.carte.echosvg.dom.util.DocumentFactory;
import io.sf.carte.echosvg.gvt.CanvasGraphicsNode;
import io.sf.carte.echosvg.gvt.CompositeGraphicsNode;
@@ -121,7 +126,6 @@ protected SVGAbstractTranscoder() {
hints.put(KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, SVGConstants.SVG_NAMESPACE_URI);
hints.put(KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG);
- hints.put(KEY_DOM_IMPLEMENTATION, SVGDOMImplementation.getDOMImplementation());
hints.put(KEY_MEDIA, "screen");
hints.put(KEY_DEFAULT_FONT_FAMILY, DEFAULT_DEFAULT_FONT_FAMILY);
hints.put(KEY_EXECUTE_ONLOAD, Boolean.FALSE);
@@ -200,23 +204,19 @@ public void transcode(TranscoderInput input, TranscoderOutput output) throws Tra
/**
* Transcodes the specified Document as an image in the specified output.
*
- * @param document the document to transcode
- * @param uri the uri of the document or null if any
- * @param output the ouput where to transcode
+ * @param document the document to transcode. Cannot be {@code null}.
+ * @param uri the uri of the document or {@code null} if any.
+ * @param output the ouput where to transcode.
* @exception TranscoderException if an error occured while transcoding
*/
@Override
protected void transcode(Document document, String uri, TranscoderOutput output) throws TranscoderException {
-
- if ((document != null) && !(document.getImplementation() instanceof SVGDOMImplementation)) {
- DOMImplementation impl;
- impl = (DOMImplementation) hints.get(KEY_DOM_IMPLEMENTATION);
- // impl = SVGDOMImplementation.getDOMImplementation();
- document = DOMUtilities.deepCloneDocument(document, impl);
- if (uri != null) {
- ParsedURL url = new ParsedURL(uri);
- ((SVGOMDocument) document).setParsedURL(url);
- }
+ SVGOMDocument svgDoc;
+ // document is assumed to be non-null here
+ if (!(document instanceof SVGOMDocument)) {
+ svgDoc = getSVGDocument(document, uri);
+ } else {
+ svgDoc = (SVGOMDocument) document;
}
if (hints.containsKey(KEY_WIDTH))
@@ -224,7 +224,6 @@ protected void transcode(Document document, String uri, TranscoderOutput output)
if (hints.containsKey(KEY_HEIGHT))
height = (Float) hints.get(KEY_HEIGHT);
- SVGOMDocument svgDoc = (SVGOMDocument) document;
SVGSVGElement root = svgDoc.getRootElement();
ctx = createBridgeContext(svgDoc);
@@ -321,6 +320,85 @@ protected void transcode(Document document, String uri, TranscoderOutput output)
this.root = gvtRoot;
}
+ private SVGOMDocument getSVGDocument(Document document, String uri) {
+ // Obtain the document element and DocumentType
+ DocumentType docType;
+ Element docElm = document.getDocumentElement();
+ // Check whether the document element is a SVG element anyway
+ if (docElm.getNamespaceURI() != SVGDOMImplementation.SVG_NAMESPACE_URI
+ && !"SVG".equalsIgnoreCase(docElm.getTagName())) {
+ // Not a SVG document, get the first SVG element
+ docElm = (Element) document.getElementsByTagNameNS("*", SVGConstants.SVG_SVG_TAG).item(0);
+ docType = null;
+ } else {
+ docType = document.getDoctype();
+ }
+
+ // Obtain a DOM implementation
+ DOMImplementation impl;
+ impl = (DOMImplementation) hints.get(KEY_DOM_IMPLEMENTATION);
+ if (impl == null) {
+ // Look for the version attribute of the root element
+ if ("1.2".equals(docElm.getAttribute(SVGConstants.SVG_VERSION_ATTRIBUTE))) {
+ impl = SVG12DOMImplementation.getDOMImplementation();
+ } else {
+ impl = SVGDOMImplementation.getDOMImplementation();
+ }
+ }
+
+ // Clone the document
+ SVGOMDocument svgDocument = (SVGOMDocument) deepCloneDocument(document, docElm, docType, impl);
+
+ if (uri != null) {
+ ParsedURL url = new ParsedURL(uri);
+ svgDocument.setParsedURL(url);
+ }
+
+ return svgDocument;
+ }
+
+ private static Document deepCloneDocument(Document doc, Element root, DocumentType docType,
+ DOMImplementation impl) {
+ Document result = impl.createDocument(root.getNamespaceURI(), root.getNodeName(), docType);
+ Element rroot = result.getDocumentElement();
+
+ // Let's see if the designed root node is also the origin's document root
+ boolean before = root.getParentNode().getNodeType() == Node.DOCUMENT_NODE;
+ Node firstNode;
+ if (before) {
+ firstNode = doc.getFirstChild();
+ } else {
+ firstNode = root;
+ }
+
+ for (Node n = firstNode; n != null; n = n.getNextSibling()) {
+ if (n == root) {
+ before = false;
+ if (root.hasAttributes()) {
+ NamedNodeMap attr = root.getAttributes();
+ int len = attr.getLength();
+ for (int i = 0; i < len; i++) {
+ rroot.setAttributeNode((Attr) result.importNode(attr.item(i), true));
+ }
+ }
+ for (Node c = root.getFirstChild(); c != null; c = c.getNextSibling()) {
+ rroot.appendChild(result.importNode(c, true));
+ }
+ } else {
+ short type = n.getNodeType();
+ if (type == Node.COMMENT_NODE || type == Node.PROCESSING_INSTRUCTION_NODE) {
+ if (before) {
+ result.insertBefore(result.importNode(n, true), rroot);
+ } else {
+ result.appendChild(result.importNode(n, true));
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
protected CanvasGraphicsNode getCanvasGraphicsNode(GraphicsNode gn) {
if (!(gn instanceof CompositeGraphicsNode))
return null;
diff --git a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/XMLAbstractTranscoder.java b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/XMLAbstractTranscoder.java
index 2044a0396..f4ffc7699 100644
--- a/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/XMLAbstractTranscoder.java
+++ b/echosvg-transcoder/src/main/java/io/sf/carte/echosvg/transcoder/XMLAbstractTranscoder.java
@@ -25,6 +25,8 @@
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
+import io.sf.carte.echosvg.anim.dom.SVGDOMImplementation;
+import io.sf.carte.echosvg.dom.GenericDOMImplementation;
import io.sf.carte.echosvg.dom.util.DocumentFactory;
import io.sf.carte.echosvg.dom.util.SAXDocumentFactory;
import io.sf.carte.echosvg.transcoder.keys.BooleanKey;
@@ -37,13 +39,20 @@
* advantage of this class, you have to specify the following transcoding hints:
*
* KEY_DOM_IMPLEMENTATION
: the DOM Implementation to use
+ * KEY_DOM_IMPLEMENTATION
: the DOM Implementation to use. If no
+ * hint is provided a SVG 1.1 implementation shall be used, or a 1.2 if the
+ * input is a DOM Document
where the SVG root has a 1.2
+ * version
attribute.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI
: the namespace URI of the
- * document to create
+ * document to create. By default it is the SVG namespace URI. If you want to
+ * process a svg
element embedded into a XHTML document, it should
+ * be the XHTML namespace URI.KEY_DOCUMENT_ELEMENT
: the qualified name of the document
- * type to create
+ * element to create. By default it is the svg
element. If you want
+ * to process a svg
element embedded into a XHTML document, it must
+ * be the html
element.DocumentFactory
used to create the DOM tree.
* Override this method if you have to use another implementation of the
diff --git a/samples/tests/spec/styling/css2.xhtml b/samples/tests/spec/styling/css2.xhtml
new file mode 100644
index 000000000..92586bbd7
--- /dev/null
+++ b/samples/tests/spec/styling/css2.xhtml
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+