From: Vincent Hennebert Date: Mon, 18 Apr 2011 18:36:05 +0000 (+0000) Subject: Added id element to intermediate format to track the origin of content. X-Git-Tag: fop-1_1rc1old~237 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=427df0fa7d2f67a4d21740cbf7264d3b11739a41;p=xmlgraphics-fop.git Added id element to intermediate format to track the origin of content. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1094690 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/build.xml b/build.xml index 114a14e27..cfad23a74 100644 --- a/build.xml +++ b/build.xml @@ -927,7 +927,12 @@ list of possible build targets. testsuite="org.apache.fop.intermediate.AreaTreeXMLFormatTestSuite" outfile="TEST-area-tree-xml-format"/> - + + + + + + + + diff --git a/src/java/org/apache/fop/render/intermediate/IFConstants.java b/src/java/org/apache/fop/render/intermediate/IFConstants.java index 34fe2bd2c..2b16b343d 100644 --- a/src/java/org/apache/fop/render/intermediate/IFConstants.java +++ b/src/java/org/apache/fop/render/intermediate/IFConstants.java @@ -67,6 +67,8 @@ public interface IFConstants extends XMLConstants { String EL_FONT = "font"; /** element name text */ String EL_TEXT = "text"; + /** element name id */ + String EL_ID = "id"; /** Parent element of the logical structure tree. */ String EL_STRUCTURE_TREE = "structure-tree"; } diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index 804b353c1..b8be97253 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -48,6 +48,8 @@ public class IFContext { private String structurePointer; + private String id = ""; + /** * Main constructor. * @param ua the user agent @@ -155,4 +157,23 @@ public class IFContext { return this.structurePointer; } + /** + * Sets the ID of the object enclosing the content that will follow. + * + * @param id the ID of the nearest ancestor object for which the id property was set + */ + void setID(String id) { + assert id != null; + this.id = id; + } + + /** + * Returns the ID of the object enclosing the current content. + * + * @return the ID of the nearest ancestor object for which the id property was set + */ + String getID() { + return id; + } + } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 645d1ebc6..313cee685 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -24,6 +24,7 @@ import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; +import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -76,7 +77,7 @@ public class IFParser implements IFConstants { private static SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); - private static Set handledNamespaces = new java.util.HashSet(); + private static Set handledNamespaces = new java.util.HashSet(); static { handledNamespaces.add(XMLNS_NAMESPACE_URI); @@ -132,7 +133,7 @@ public class IFParser implements IFConstants { private static class Handler extends DefaultHandler { - private Map elementHandlers = new java.util.HashMap(); + private Map elementHandlers = new HashMap(); private IFDocumentHandler documentHandler; private IFPainter painter; @@ -188,6 +189,7 @@ public class IFParser implements IFConstants { //Page content elementHandlers.put(EL_VIEWPORT, new ViewportHandler()); elementHandlers.put(EL_GROUP, new GroupHandler()); + elementHandlers.put(EL_ID, new IDHandler()); elementHandlers.put(EL_FONT, new FontHandler()); elementHandlers.put(EL_TEXT, new TextHandler()); elementHandlers.put(EL_CLIP_RECT, new ClipRectHandler()); @@ -202,7 +204,7 @@ public class IFParser implements IFConstants { } } - private void establishForeignAttributes(Map foreignAttributes) { + private void establishForeignAttributes(Map foreignAttributes) { documentHandler.getContext().setForeignAttributes(foreignAttributes); } @@ -300,7 +302,7 @@ public class IFParser implements IFConstants { private boolean startIFElement(String localName, Attributes attributes) throws SAXException { lastAttributes = new AttributesImpl(attributes); - ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName); + ElementHandler elementHandler = elementHandlers.get(localName); content.setLength(0); ignoreCharacters = true; if (elementHandler != null) { @@ -346,7 +348,7 @@ public class IFParser implements IFConstants { } } else { if (NAMESPACE.equals(uri)) { - ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName); + ElementHandler elementHandler = elementHandlers.get(localName); if (elementHandler != null) { try { elementHandler.endElement(); @@ -432,7 +434,7 @@ public class IFParser implements IFConstants { documentHandler.getContext().setLanguage( XMLUtil.convertRFC3066ToLocale(xmllang)); } - Map foreignAttributes = getForeignAttributes(lastAttributes); + Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); documentHandler.startPageSequence(id); resetForeignAttributes(); @@ -453,7 +455,7 @@ public class IFParser implements IFConstants { String pageMasterName = attributes.getValue("page-master-name"); int width = Integer.parseInt(attributes.getValue("width")); int height = Integer.parseInt(attributes.getValue("height")); - Map foreignAttributes = getForeignAttributes(lastAttributes); + Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); documentHandler.startPage(index, name, pageMasterName, new Dimension(width, height)); @@ -486,6 +488,7 @@ public class IFParser implements IFConstants { public void endElement() throws IFException { painter = null; + documentHandler.getContext().setID(""); documentHandler.endPageContent(); } @@ -536,6 +539,16 @@ public class IFParser implements IFConstants { } + private class IDHandler extends AbstractElementHandler { + + @Override + public void startElement(Attributes attributes) throws IFException, SAXException { + String id = attributes.getValue("name"); + documentHandler.getContext().setID(id); + } + + } + private class FontHandler extends AbstractElementHandler { public void startElement(Attributes attributes) throws IFException { @@ -660,7 +673,7 @@ public class IFParser implements IFConstants { int y = Integer.parseInt(lastAttributes.getValue("y")); int width = Integer.parseInt(lastAttributes.getValue("width")); int height = Integer.parseInt(lastAttributes.getValue("height")); - Map foreignAttributes = getForeignAttributes(lastAttributes); + Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); setStructurePointer(lastAttributes); if (foreignObject != null) { @@ -712,8 +725,8 @@ public class IFParser implements IFConstants { } } - private static Map getForeignAttributes(Attributes atts) { - Map foreignAttributes = null; + private static Map getForeignAttributes(Attributes atts) { + Map foreignAttributes = null; for (int i = 0, c = atts.getLength(); i < c; i++) { String ns = atts.getURI(i); if (ns.length() > 0) { @@ -721,7 +734,7 @@ public class IFParser implements IFConstants { continue; } if (foreignAttributes == null) { - foreignAttributes = new java.util.HashMap(); + foreignAttributes = new java.util.HashMap(); } QName qname = new QName(ns, atts.getQName(i)); foreignAttributes.put(qname, atts.getValue(i)); diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index c81a5cae9..24a2e8a75 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -153,6 +153,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer { private TextUtil textUtil = new TextUtil(); + private Stack ids = new Stack(); + /** * Main constructor */ @@ -841,11 +843,13 @@ public class IFRenderer extends AbstractPathOrientedRenderer { public void renderInlineViewport(InlineViewport viewport) { String ptr = (String) viewport.getTrait(Trait.PTR); establishStructurePointer(ptr); + pushdID(viewport); Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD()); viewportDimensionStack.push(dim); super.renderInlineViewport(viewport); viewportDimensionStack.pop(); resetStructurePointer(); + popID(viewport); } /** {@inheritDoc} */ @@ -888,7 +892,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer { /** {@inheritDoc} */ protected void renderInlineArea(InlineArea inlineArea) { saveInlinePosIfTargetable(inlineArea); + pushdID(inlineArea); super.renderInlineArea(inlineArea); + popID(inlineArea); } /** {@inheritDoc} */ @@ -952,7 +958,25 @@ public class IFRenderer extends AbstractPathOrientedRenderer { log.trace("renderBlock() " + block); } saveBlockPosIfTargetable(block); + pushdID(block); super.renderBlock(block); + popID(block); + } + + private void pushdID(Area area) { + String prodID = (String) area.getTrait(Trait.PROD_ID); + if (prodID != null) { + ids.push(prodID); + documentHandler.getContext().setID(prodID); + } + } + + private void popID(Area area) { + String prodID = (String) area.getTrait(Trait.PROD_ID); + if (prodID != null) { + ids.pop(); + documentHandler.getContext().setID(ids.empty() ? "" : ids.peek()); + } } private Typeface getTypeface(String fontName) { diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index d906d4189..471a982ca 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -69,6 +69,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** Holds the intermediate format state */ private IFState state; + private String currentID = ""; + /** * Default constructor. */ @@ -306,6 +308,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void endPageContent() throws IFException { try { this.state = null; + currentID = ""; handler.endElement(EL_PAGE_CONTENT); } catch (SAXException e) { throw new IFException("SAX error in endPageContent()", e); @@ -417,6 +420,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect) throws IFException { try { + addID(); AttributesImpl atts = new AttributesImpl(); addAttribute(atts, XLINK_HREF, uri); addAttribute(atts, "x", Integer.toString(rect.x)); @@ -445,6 +449,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void drawImage(Document doc, Rectangle rect) throws IFException { try { + addID(); AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "x", Integer.toString(rect.x)); addAttribute(atts, "y", Integer.toString(rect.y)); @@ -534,6 +539,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void drawLine(Point start, Point end, int width, Color color, RuleStyle style) throws IFException { try { + addID(); AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "x1", Integer.toString(start.x)); addAttribute(atts, "y1", Integer.toString(start.y)); @@ -552,6 +558,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) throws IFException { try { + addID(); AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "x", Integer.toString(x)); addAttribute(atts, "y", Integer.toString(y)); @@ -671,7 +678,16 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } } - // ---=== IFDocumentNavigationHandler ===--- + private void addID() throws SAXException { + String id = getContext().getID(); + if (!currentID.equals(id)) { + AttributesImpl atts = new AttributesImpl(); + addAttribute(atts, "name", id); + handler.startElement(EL_ID, atts); + handler.endElement(EL_ID); + currentID = id; + } + } private Map incompleteActions = new java.util.HashMap(); private List completeActions = new java.util.LinkedList(); diff --git a/status.xml b/status.xml index ec037b6e0..9378e627f 100644 --- a/status.xml +++ b/status.xml @@ -59,6 +59,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Added id element to intermediate format to track the origin of content. + Bugzilla 50988: Fixed a NullPointerException in case a white-space fo:character was removed due to white-space handling. diff --git a/test/intermediate/block-container.xml b/test/intermediate/block-container.xml new file mode 100644 index 000000000..5749de28f --- /dev/null +++ b/test/intermediate/block-container.xml @@ -0,0 +1,64 @@ + + + + +

+ This test checks that IDs coming from a block-container properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + In vel libero libero, a semper est. Vivamus dapibus ante id + lorem mattis eget mattis urna sodales. Vestibulum nec dui urna, in porta + mi. + Proin varius egestas erat. Proin ante eros, consequat eget + semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus. + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/block-container_nested.xml b/test/intermediate/block-container_nested.xml new file mode 100644 index 000000000..40f9903ff --- /dev/null +++ b/test/intermediate/block-container_nested.xml @@ -0,0 +1,148 @@ + + + + +

+ This test checks that IDs coming from a block-container properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + + In vel libero libero, a semper est. Vivamus dapibus ante id lorem mattis eget + mattis urna sodales. + + Vestibulum nec dui urna, in porta mi. Proin varius egestas + erat. Donec pharetra iaculis dolor, ut rutrum nunc facilisis + at. + + Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel + leo luctus dapibus. + + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + + Sed ultrices posuere posuere. Praesent vitae ligula odio. + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + + In vel libero libero, a semper est. Vivamus dapibus ante id lorem mattis eget + mattis urna sodales. + Mauris tincidunt, risus eget vulputate elementum, + turpis lorem aliquet purus, eu sagittis neque sapien vel lectus. + + Vestibulum nec dui urna, in porta mi. Proin varius egestas erat. Donec + pharetra iaculis dolor, ut rutrum nunc facilisis at. + + Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel + leo luctus dapibus. + Vivamus ut sollicitudin metus. Curabitur sit amet aliquam + enim. + + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + + Vivamus tellus libero, porttitor a lacinia a, tempor eu dui. Pellentesque + fermentum odio tempor lorem interdum pharetra. + + Donec auctor venenatis convallis. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/block.xml b/test/intermediate/block.xml new file mode 100644 index 000000000..1801bb7c6 --- /dev/null +++ b/test/intermediate/block.xml @@ -0,0 +1,63 @@ + + + + +

+ This test checks that IDs coming from a block properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + In vel libero + libero, a semper est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. + Vestibulum nec dui urna, in porta mi. + Proin varius egestas erat. Proin ante eros, consequat eget + semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus. + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/block_nested.xml b/test/intermediate/block_nested.xml new file mode 100644 index 000000000..5ec8af00f --- /dev/null +++ b/test/intermediate/block_nested.xml @@ -0,0 +1,138 @@ + + + + +

+ This test checks that IDs coming from a block properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + In vel libero libero, a semper + est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. + Vestibulum nec dui urna, in + porta mi. Proin varius egestas erat. Donec pharetra iaculis dolor, ut rutrum nunc + facilisis at. + Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel + leo luctus dapibus. + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + Sed ultrices posuere posuere. + Praesent vitae ligula odio. + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + In vel libero libero, a semper + est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. + Mauris tincidunt, risus eget vulputate elementum, + turpis lorem aliquet purus, eu sagittis neque sapien vel lectus. + Vestibulum nec dui urna, in + porta mi. Proin varius egestas erat. Donec pharetra iaculis dolor, ut rutrum nunc + facilisis at. + Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel + leo luctus dapibus. + Vivamus ut sollicitudin metus. Curabitur sit amet aliquam enim. + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + Vivamus tellus libero, porttitor a + lacinia a, tempor eu dui. Pellentesque fermentum odio tempor lorem interdum + pharetra. + Donec auctor venenatis convallis. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/block_span_pages.xml b/test/intermediate/block_span_pages.xml new file mode 100644 index 000000000..43aff0ac4 --- /dev/null +++ b/test/intermediate/block_span_pages.xml @@ -0,0 +1,126 @@ + + + + +

+ This test checks that IDs coming from a block that spans over different pages properly appear + in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. + In vel libero libero, a + semper est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. Proin ante + eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel leo + luctus dapibus. + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. + In vel libero libero, a semper + est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. + Vestibulum nec dui urna, in + porta mi. Proin varius egestas erat. Donec pharetra iaculis dolor, ut rutrum nunc + facilisis at. Sed ultrices posuere posuere. Praesent vitae ligula odio. Vivamus + porttitor sollicitudin tortor eu vulputate. + Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel + leo luctus dapibus. + Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit. + Suspendisse fermentum fermentum ullamcorper. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/images.xml b/test/intermediate/images.xml new file mode 100644 index 000000000..08ca83f5c --- /dev/null +++ b/test/intermediate/images.xml @@ -0,0 +1,93 @@ + + + + +

+ This test checks that IDs coming from images properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. In vel + libero libero, a semper est. + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. + + + + + + + + Vivamus porttitor sollicitudin tortor eu vulputate. In vel + libero libero, a semper est. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/inlines.xml b/test/intermediate/inlines.xml new file mode 100644 index 000000000..eb588992a --- /dev/null +++ b/test/intermediate/inlines.xml @@ -0,0 +1,107 @@ + + + + +

+ This test checks that IDs coming from various inline elements properly appear in the IF + output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, onsectetur adipiscing + elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. In vel + libero libero, a semper est. Vivamus dapibus ante id lorem mattis eget mattis urna + sodales. This is page number . Vestibulum + nec dui urna, in porta mi. The fo:character object is on page . Proin varius egestas erat. + Proin ante eros, consequat eget semper a, molestie non arcu. The last page of this document + is page . Praesent hendrerit dolor vel leo luctus dapibus. + + Lorem ipsum dolor sit amet, consectetur adipiscing + elit. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/list.xml b/test/intermediate/list.xml new file mode 100644 index 000000000..81283ce5e --- /dev/null +++ b/test/intermediate/list.xml @@ -0,0 +1,112 @@ + + + + +

+ This test checks that IDs coming from the various elements of a list properly appear in the IF + output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + + + + • + + + Item 1 + id="list-item-body" + + + + + • + + + Item 2 + id="list-item_2" + + + + + • + + + Item 3 + id="list-block" + + + + In vel libero + libero, a semper est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales. + Vestibulum nec dui urna, in porta mi. + Proin varius egestas erat. Proin ante eros, consequat eget + semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/intermediate/table.xml b/test/intermediate/table.xml new file mode 100644 index 000000000..4e3d10cbf --- /dev/null +++ b/test/intermediate/table.xml @@ -0,0 +1,146 @@ + + + + +

+ This test checks that IDs coming from the various elements of a table properly appear in the IF output. +

+
+ + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam + bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate. + + + + Header 1.1 + id="table-cell_header_1.1" + + + Header 1.2 id="table-header" + + + + + + Cell 1.1 id="table-cell_1.1" + + + Cell 1.2 id="table-row_1" + + + + + Cell 2.1 id="table-body_1" + + + Cell 2.2 id="table-body_1" + + + + + + + Cell 3.1 id="table-cell_3.1" + + + Cell 3.2 id="table-row_3" + + + + + Cell 4.1 id="block" + + + Cell 4.2 id="table" + + + + + Proin varius egestas erat. Proin ante eros, consequat eget + semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus. + Mauris ac erat est, sit amet + dignissim elit. Ut pulvinar diam ut lorem pellentesque tempus. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/java/org/apache/fop/check/Check.java b/test/java/org/apache/fop/check/Check.java new file mode 100644 index 000000000..ffc7e3cbc --- /dev/null +++ b/test/java/org/apache/fop/check/Check.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.check; + +/** + * A marker interface to identify checks in XML test cases. + */ +public interface Check { + +} diff --git a/test/java/org/apache/fop/check/ChecksFactory.java b/test/java/org/apache/fop/check/ChecksFactory.java new file mode 100644 index 000000000..a493c09f2 --- /dev/null +++ b/test/java/org/apache/fop/check/ChecksFactory.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.check; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A factory class for creating checks that belong to a same family. + * @param a family of checks + */ +public abstract class ChecksFactory { + + /** + * A factory to create a particular kind of check. + */ + protected static interface CheckFactory { + + /** + * Creates a {@link Check} instance from the given XML element. + * + * @param element an element representing a check + * @return the corresponding check + */ + C createCheck(Element element); + } + + private final Map> checkFactories + = new HashMap>(); + + /** Default constructor. */ + protected ChecksFactory() { } + + /** + * Registers a factory for a new kind of check. + * + * @param elementName the name of the element under which the check is identified in + * the XML test case + * @param factory the corresponding factory + */ + protected void registerCheckFactory(String elementName, CheckFactory factory) { + checkFactories.put(elementName, factory); + } + + /** + * Creates a new {@link Check} instance corresponding to the given element. + * + * @param element an element in the XML test case that identifies a particular check + * @return the corresponding check + * @throws IllegalArgumentException if not check corresponding to the given element + * has been found + */ + public final C createCheck(Element element) { + String name = element.getTagName(); + CheckFactory factory = checkFactories.get(name); + if (factory == null) { + throw new IllegalArgumentException("No check class found for " + name); + } else { + return factory.createCheck(element); + } + } + + public final List createCheckList(Element container) { + List checks = new ArrayList(); + NodeList nodes = container.getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + if (node instanceof Element) { + checks.add(createCheck((Element) node)); + } + } + return checks; + } +} diff --git a/test/java/org/apache/fop/check/package-info.java b/test/java/org/apache/fop/check/package-info.java new file mode 100644 index 000000000..5785f7a4b --- /dev/null +++ b/test/java/org/apache/fop/check/package-info.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +/** + * A framework for creating checks from elements stored in an XML test case. The test case + * typically contains the XML document under test, along with a series of checks expressed + * as XML elements. + */ +package org.apache.fop.check; diff --git a/test/java/org/apache/fop/intermediate/AbstractIFTestCase.java b/test/java/org/apache/fop/intermediate/AbstractIFTestCase.java new file mode 100644 index 000000000..56d613e20 --- /dev/null +++ b/test/java/org/apache/fop/intermediate/AbstractIFTestCase.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.intermediate; + +import java.io.File; +import java.io.IOException; + +import javax.xml.XMLConstants; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.w3c.dom.Document; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.apps.Fop; +import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFDocumentHandler; +import org.apache.fop.render.intermediate.IFSerializer; + +/** + * A common super-class for intermediate format test cases. + */ +abstract class AbstractIFTestCase extends AbstractIntermediateTestCase { + + private static final Schema IF_SCHEMA; + + static { + Schema ifSchema = null; + try { + SchemaFactory sFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + File ifSchemaFile = new File( + "src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd"); + ifSchema = sFactory.newSchema(ifSchemaFile); + } catch (IllegalArgumentException iae) { + System.err.println("No suitable SchemaFactory for XML Schema validation found!"); + } catch (SAXException e) { + throw new ExceptionInInitializerError(e); + } + IF_SCHEMA = ifSchema; + } + + /** + * Creates a new test case. + * + * @param testFile the file containing the document and the tests + * @throws IOException if an I/O error occurs while loading the test case + */ + public AbstractIFTestCase(File testFile) throws IOException { + super(testFile); + } + + @Override + protected String getIntermediateFileExtension() { + return ".if.xml"; + } + + @Override + protected Document buildIntermediateDocument(Templates templates) throws Exception { + Transformer transformer = templates.newTransformer(); + setErrorListener(transformer); + + //Set up XMLRenderer to render to a DOM + DOMResult domResult = new DOMResult(); + + FOUserAgent userAgent = createUserAgent(); + + //Create an instance of the target renderer so the XMLRenderer can use its font setup + IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler( + userAgent, getTargetMIME()); + + //Setup painter + IFSerializer serializer = new IFSerializer(); + serializer.setContext(new IFContext(userAgent)); + serializer.mimicDocumentHandler(targetHandler); + serializer.setResult(domResult); + + userAgent.setDocumentHandlerOverride(serializer); + + Fop fop = fopFactory.newFop(userAgent); + Result res = new SAXResult(fop.getDefaultHandler()); + transformer.transform(new DOMSource(testDoc), res); + + return (Document) domResult.getNode(); + } + + @Override + protected void validate(Document doc) throws SAXException, IOException { + if (IF_SCHEMA == null) { + return; //skip validation; + } + Validator validator = IF_SCHEMA.newValidator(); + validator.setErrorHandler(new ErrorHandler() { + + public void error(SAXParseException exception) throws SAXException { + throw exception; + } + + public void fatalError(SAXParseException exception) throws SAXException { + throw exception; + } + + public void warning(SAXParseException exception) throws SAXException { + //ignore + } + + }); + validator.validate(new DOMSource(doc)); + } + +} diff --git a/test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java b/test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java index 826a5c777..d16621382 100644 --- a/test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java +++ b/test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java @@ -44,7 +44,6 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; import org.apache.fop.events.model.EventSeverity; -import org.apache.fop.layoutengine.TestEnvironment; import org.apache.fop.util.ConsoleEventListenerForTests; /** @@ -53,15 +52,13 @@ import org.apache.fop.util.ConsoleEventListenerForTests; public abstract class AbstractIntermediateTestCase extends XMLTestCase { /** the test environment */ - protected static TestEnvironment env = new TestEnvironment(); + protected static TestAssistant testAssistant = new TestAssistant(); /** the FOP factory */ protected FopFactory fopFactory; - /** the main base directory for tests */ - protected File mainDir = new File("test/layoutengine"); /** the directory containing the tests */ - protected File testDir = new File(mainDir, "standard-testcases"); + protected File testDir = new File("test/layoutengine/standard-testcases"); /** the output directory for any files generated by the tests */ protected File outputDir; @@ -87,11 +84,11 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase { protected void setUp() throws Exception { super.setUp(); setupOutputDirectory(); - this.testDoc = env.loadTestCase(testFile); - this.fopFactory = env.getFopFactory(testDoc); - intermediate = buildIntermediateDocument(env.getTestcase2FOStylesheet()); + this.testDoc = testAssistant.loadTestCase(testFile); + this.fopFactory = testAssistant.getFopFactory(testDoc); + intermediate = buildIntermediateDocument(testAssistant.getTestcase2FOStylesheet()); if (outputDir != null) { - env.saveDOM(intermediate, new File(outputDir, + testAssistant.saveDOM(intermediate, new File(outputDir, getName() + ".1" + getIntermediateFileExtension())); } } @@ -148,7 +145,8 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase { userAgent.getEventBroadcaster().addEventListener( new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.FATAL)); } catch (MalformedURLException e) { - //ignore, won't happen + // Shouldn't happen + throw new AssertionError(); } return userAgent; } @@ -175,7 +173,7 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase { Document doc = parseAndRenderToIntermediateFormat(src); if (outputDir != null) { File tgtFile = new File(outputDir, getName() + ".2" + getIntermediateFileExtension()); - env.saveDOM(doc, tgtFile); + testAssistant.saveDOM(doc, tgtFile); } assertXMLEqual(intermediate, doc); diff --git a/test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java b/test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java index 3d029778d..e3135c5a3 100644 --- a/test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java +++ b/test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java @@ -72,7 +72,7 @@ public class AreaTreeParserTestCase extends AbstractIntermediateTestCase { setErrorListener(transformer); //Set up XMLRenderer to render to a DOM - TransformerHandler handler = env.getTransformerFactory().newTransformerHandler(); + TransformerHandler handler = testAssistant.getTransformerFactory().newTransformerHandler(); DOMResult domResult = new DOMResult(); handler.setResult(domResult); @@ -113,7 +113,7 @@ public class AreaTreeParserTestCase extends AbstractIntermediateTestCase { AreaTreeParser parser = new AreaTreeParser(); //Set up XMLRenderer to render to a DOM - TransformerHandler handler = env.getTransformerFactory().newTransformerHandler(); + TransformerHandler handler = testAssistant.getTransformerFactory().newTransformerHandler(); DOMResult domResult = new DOMResult(); handler.setResult(domResult); XMLRenderer renderer = new XMLRenderer(); diff --git a/test/java/org/apache/fop/intermediate/IFCheck.java b/test/java/org/apache/fop/intermediate/IFCheck.java index dc5404818..dfd76f3b3 100644 --- a/test/java/org/apache/fop/intermediate/IFCheck.java +++ b/test/java/org/apache/fop/intermediate/IFCheck.java @@ -21,10 +21,12 @@ package org.apache.fop.intermediate; import org.w3c.dom.Document; +import org.apache.fop.check.Check; + /** * Check interface for intermediate format checks. */ -public interface IFCheck { +public interface IFCheck extends Check { /** * Called to perform the check. diff --git a/test/java/org/apache/fop/intermediate/IFChecksFactory.java b/test/java/org/apache/fop/intermediate/IFChecksFactory.java new file mode 100644 index 000000000..2eab74130 --- /dev/null +++ b/test/java/org/apache/fop/intermediate/IFChecksFactory.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.intermediate; + +import org.w3c.dom.Element; + +import org.apache.fop.check.ChecksFactory; +import org.apache.fop.layoutengine.EvalCheck; +import org.apache.fop.layoutengine.TrueCheck; + +/** + * A factory class for creating {@link IFCheck} instances. + */ +final class IFChecksFactory extends ChecksFactory { + + IFChecksFactory() { + registerCheckFactory("true", new CheckFactory() { + + public IFCheck createCheck(Element element) { + return new TrueCheck(element); + } + + }); + registerCheckFactory("eval", new CheckFactory() { + + public IFCheck createCheck(Element element) { + return new EvalCheck(element); + } + + }); + } +} diff --git a/test/java/org/apache/fop/intermediate/IFParserTestCase.java b/test/java/org/apache/fop/intermediate/IFParserTestCase.java index 15fc74bc9..afdd757c9 100644 --- a/test/java/org/apache/fop/intermediate/IFParserTestCase.java +++ b/test/java/org/apache/fop/intermediate/IFParserTestCase.java @@ -23,59 +23,23 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; -import javax.xml.XMLConstants; -import javax.xml.transform.Result; import javax.xml.transform.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; import org.w3c.dom.Document; -import org.xml.sax.ErrorHandler; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.Fop; -import org.apache.fop.apps.MimeConstants; import org.apache.fop.fonts.FontInfo; -import org.apache.fop.layoutengine.TestEnvironment; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFParser; -import org.apache.fop.render.intermediate.IFRenderer; import org.apache.fop.render.intermediate.IFSerializer; /** * Tests the intermediate format parser. */ -public class IFParserTestCase extends AbstractIntermediateTestCase { - - private static TestEnvironment env = new TestEnvironment(); - private static Schema ifSchema; - - private static Schema getIFSchema() throws SAXException { - if (ifSchema == null) { - SchemaFactory sFactory; - try { - sFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - } catch (IllegalArgumentException iae) { - System.out.println("No suitable SchemaFactory for XML Schema validation found!"); - return null; - } - File ifSchemaFile = new File( - "src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd"); - ifSchema = sFactory.newSchema(ifSchemaFile); - } - return ifSchema; - } +public class IFParserTestCase extends AbstractIFTestCase { /** * Constructor for the test suite that is used for each test file. @@ -87,76 +51,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase { } /** {@inheritDoc} */ - protected String getTargetMIME() { - return MimeConstants.MIME_PDF; - } - - /** {@inheritDoc} */ - protected String getIntermediateFileExtension() { - return ".if.xml"; - } - - /** {@inheritDoc} */ - protected Document buildIntermediateDocument(Templates templates) - throws Exception { - Transformer transformer = templates.newTransformer(); - setErrorListener(transformer); - - //Set up XMLRenderer to render to a DOM - DOMResult domResult = new DOMResult(); - - FOUserAgent userAgent = createUserAgent(); - - //Create an instance of the target renderer so the XMLRenderer can use its font setup - IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler( - userAgent, getTargetMIME()); - - //Setup painter - IFSerializer serializer = new IFSerializer(); - serializer.setContext(new IFContext(userAgent)); - serializer.mimicDocumentHandler(targetHandler); - serializer.setResult(domResult); - - //Setup renderer - IFRenderer renderer = new IFRenderer(); - renderer.setUserAgent(userAgent); - - renderer.setDocumentHandler(serializer); - userAgent.setRendererOverride(renderer); - - Fop fop = fopFactory.newFop(userAgent); - Result res = new SAXResult(fop.getDefaultHandler()); - transformer.transform(new DOMSource(testDoc), res); - - return (Document)domResult.getNode(); - } - - /** {@inheritDoc} */ - protected void validate(Document doc) throws SAXException, IOException { - Schema schema = getIFSchema(); - if (schema == null) { - return; //skip validation; - } - Validator validator = schema.newValidator(); - validator.setErrorHandler(new ErrorHandler() { - - public void error(SAXParseException exception) throws SAXException { - throw exception; - } - - public void fatalError(SAXParseException exception) throws SAXException { - throw exception; - } - - public void warning(SAXParseException exception) throws SAXException { - //ignore - } - - }); - validator.validate(new DOMSource(doc)); - } - - /** {@inheritDoc} */ + @Override protected void parseAndRender(Source src, OutputStream out) throws Exception { IFParser parser = new IFParser(); @@ -170,6 +65,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase { } /** {@inheritDoc} */ + @Override protected Document parseAndRenderToIntermediateFormat(Source src) throws Exception { IFParser parser = new IFParser(); @@ -185,4 +81,11 @@ public class IFParserTestCase extends AbstractIntermediateTestCase { return (Document)domResult.getNode(); } + /** {@inheritDoc} */ + @Override + public void runTest() throws Exception { + testParserToIntermediateFormat(); + testParserToPDF(); + } + } diff --git a/test/java/org/apache/fop/intermediate/IFTestCase.java b/test/java/org/apache/fop/intermediate/IFTestCase.java new file mode 100644 index 000000000..30cb56b07 --- /dev/null +++ b/test/java/org/apache/fop/intermediate/IFTestCase.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.intermediate; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import javax.xml.transform.Source; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +/** + * Test case for the IF output. + */ +public class IFTestCase extends AbstractIFTestCase { + + private final IFTester ifTester; + + /** + * Creates a new test case. + * + * @param test the file containing the test case + * @param ifTester the helper instance that will perform checks + * @throws IOException if an I/O error occurs while loading the test case + */ + public IFTestCase(File test, IFTester ifTester) throws IOException { + super(test); + this.ifTester = ifTester; + this.testDir = test.getParentFile(); + } + + /** {@inheritDoc} */ + @Override + protected void runTest() throws Exception { + Element testRoot = testAssistant.getTestRoot(testFile); + NodeList nodes = testRoot.getElementsByTagName("if-checks"); + if (nodes.getLength() == 0) { + throw new RuntimeException("No IF check found"); + } + Element ifChecks = (Element) nodes.item(0); + + Document doc = buildIntermediateDocument(testAssistant.getTestcase2FOStylesheet()); + ifTester.doIFChecks(getName(), ifChecks, doc); + } + + @Override + protected void parseAndRender(Source src, OutputStream out) throws Exception { + throw new IllegalStateException("Not applicable to this test"); + } + + @Override + protected Document parseAndRenderToIntermediateFormat(Source src) throws Exception { + throw new IllegalStateException("Not applicable to this test"); + } + +} diff --git a/test/java/org/apache/fop/intermediate/IFTester.java b/test/java/org/apache/fop/intermediate/IFTester.java index 7534309e7..46303d874 100644 --- a/test/java/org/apache/fop/intermediate/IFTester.java +++ b/test/java/org/apache/fop/intermediate/IFTester.java @@ -20,182 +20,63 @@ package org.apache.fop.intermediate; import java.io.File; -import java.lang.reflect.Constructor; -import java.util.Iterator; import java.util.List; -import java.util.Map; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; -import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXResult; -import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; - -import org.apache.fop.apps.FOUserAgent; -import org.apache.fop.apps.FopFactory; -import org.apache.fop.area.AreaTreeModel; -import org.apache.fop.area.AreaTreeParser; -import org.apache.fop.area.RenderPagesModel; -import org.apache.fop.events.model.EventSeverity; -import org.apache.fop.fonts.FontInfo; -import org.apache.fop.layoutengine.EvalCheck; -import org.apache.fop.layoutengine.TrueCheck; -import org.apache.fop.render.intermediate.IFContext; -import org.apache.fop.render.intermediate.IFRenderer; -import org.apache.fop.render.intermediate.IFSerializer; -import org.apache.fop.util.ConsoleEventListenerForTests; -import org.apache.fop.util.DelegatingContentHandler; /** * Does tests on the intermediate format. */ public class IFTester { - private static final Map IF_CHECK_CLASSES = new java.util.HashMap(); - - static { - IF_CHECK_CLASSES.put("true", TrueCheck.class); - IF_CHECK_CLASSES.put("eval", EvalCheck.class); - } - - private FopFactory fopFactory = FopFactory.newInstance(); + private final IFChecksFactory ifChecksFactory = new IFChecksFactory(); - private SAXTransformerFactory tfactory - = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + private final TransformerFactory tfactory; private File backupDir; /** - * Main constructor + * Main constructor. + * + * @param transformerFactory the factory used to serialize the intermediate format files * @param backupDir an optional directory in which to write the serialized - * intermediate format file (may be null) + * IF files (may be null) */ - public IFTester(File backupDir) { + public IFTester(TransformerFactory transformerFactory, File backupDir) { + this.tfactory = transformerFactory; this.backupDir = backupDir; } - /** - * Factory method to create IF checks from DOM elements. - * @param el DOM element to create the check from - * @return The newly create check - */ - protected IFCheck createIFCheck(Element el) { - String name = el.getTagName(); - Class clazz = (Class)IF_CHECK_CLASSES.get(name); - if (clazz != null) { - try { - Constructor c = clazz.getDeclaredConstructor(new Class[] {Node.class}); - IFCheck instance = (IFCheck)c.newInstance(new Object[] {el}); - return instance; - } catch (Exception e) { - throw new RuntimeException("Error while instantiating check '" - + name + "': " + e.getMessage()); - } - } else { - throw new IllegalArgumentException("No check class found: " + name); - } - } - - private Document createIF(File testFile, Document areaTreeXML) throws TransformerException { - try { - FOUserAgent ua = fopFactory.newFOUserAgent(); - ua.setBaseURL(testFile.getParentFile().toURI().toURL().toExternalForm()); - ua.getEventBroadcaster().addEventListener( - new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN)); - - IFRenderer ifRenderer = new IFRenderer(); - ifRenderer.setUserAgent(ua); - - IFSerializer serializer = new IFSerializer(); - serializer.setContext(new IFContext(ua)); - DOMResult result = new DOMResult(); - serializer.setResult(result); - ifRenderer.setDocumentHandler(serializer); - - ua.setRendererOverride(ifRenderer); - FontInfo fontInfo = new FontInfo(); - //Construct the AreaTreeModel that will received the individual pages - final AreaTreeModel treeModel = new RenderPagesModel(ua, - null, fontInfo, null); - - //Iterate over all intermediate files - AreaTreeParser parser = new AreaTreeParser(); - ContentHandler handler = parser.getContentHandler(treeModel, ua); - - DelegatingContentHandler proxy = new DelegatingContentHandler() { - - public void endDocument() throws SAXException { - super.endDocument(); - //Signal the end of the processing. - //The renderer can finalize the target document. - treeModel.endDocument(); - } - - }; - proxy.setDelegateContentHandler(handler); - - Transformer transformer = tfactory.newTransformer(); - transformer.transform(new DOMSource(areaTreeXML), new SAXResult(proxy)); - - return (Document)result.getNode(); - } catch (Exception e) { - throw new TransformerException( - "Error while generating intermediate format file: " + e.getMessage(), e); - } - } - /** * Runs the intermediate format checks. - * @param testFile the original test file + * @param testName the name of the test case * @param checksRoot the root element containing the IF checks - * @param areaTreeXML the area tree XML + * @param ifDocument the IF XML * @throws TransformerException if an error occurs while transforming the content */ - public void doIFChecks(File testFile, Element checksRoot, Document areaTreeXML) - throws TransformerException { - Document ifDocument = createIF(testFile, areaTreeXML); + public void doIFChecks(String testName, Element checksRoot, Document ifDocument) + throws TransformerException { if (this.backupDir != null) { Transformer transformer = tfactory.newTransformer(); Source src = new DOMSource(ifDocument); - File targetFile = new File(this.backupDir, testFile.getName() + ".if.xml"); + File targetFile = new File(this.backupDir, testName + ".if.xml"); Result res = new StreamResult(targetFile); transformer.transform(src, res); } - - //First create check before actually running them - List checks = new java.util.ArrayList(); - NodeList nodes = checksRoot.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node instanceof Element) { - checks.add(createIFCheck((Element)node)); - } - } - + List checks = ifChecksFactory.createCheckList(checksRoot); if (checks.size() == 0) { - throw new RuntimeException("No checks are available!"); + throw new RuntimeException("No available IF check"); } - - //Run the actual tests now that we know that the checks themselves are ok - doIFChecks(checks, ifDocument); - } - - private void doIFChecks(List checks, Document ifDocument) { - Iterator i = checks.iterator(); - while (i.hasNext()) { - IFCheck check = (IFCheck)i.next(); + for (IFCheck check : checks) { check.check(ifDocument); } } diff --git a/test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java b/test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java index 438ff7672..824fee6fd 100644 --- a/test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java +++ b/test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java @@ -20,52 +20,48 @@ package org.apache.fop.intermediate; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; + +import javax.xml.transform.TransformerFactory; import junit.framework.Test; import junit.framework.TestSuite; -import org.apache.fop.layoutengine.LayoutEngineTestSuite; - /** - * JUnit test suite for the intermediate format + * A test suite for testing the Intermediate Format output. */ -public class IntermediateFormatTestSuite { +public final class IntermediateFormatTestSuite { + + private IntermediateFormatTestSuite() { + // This is a utility class + } /** - * @return the test suite with all the tests (one for each XML file) - * @throws IOException in case of an I/O problem + * Creates a suite of Intermediate Format tests. + * + * @return the test suite + * @throws IOException if an I/O error occurs while loading one of the tests */ public static Test suite() throws IOException { - TestSuite suite = new TestSuite(); - Collection files = LayoutEngineTestSuite.getTestFiles(); + File backupDir = new File("build/test-results/intermediate"); + backupDir.mkdirs(); - Iterator i = files.iterator(); - while (i.hasNext()) { - File f = (File)i.next(); - addIFTestCase(suite, f); - } + IFTester ifTester = new IFTester(TransformerFactory.newInstance(), backupDir); - return suite; - } + TestSuite suite = new TestSuite(); + File testDir = new File("test/intermediate"); + String[] tests = testDir.list(new FilenameFilter() { - private static void addIFTestCase(TestSuite suite, - final File f) throws IOException { - suite.addTest(new IFParserTestCase(f) { - public void runTest() throws Exception { - try { - testParserToIntermediateFormat(); - testParserToPDF(); - } catch (Exception e) { - org.apache.commons.logging.LogFactory.getLog( - this.getClass()).error("Error on " + f.getName()); - throw e; - } + public boolean accept(File dir, String name) { + return name.endsWith(".xml"); } }); + for (String test : tests) { + File testFile = new File(testDir, test); + suite.addTest(new IFTestCase(testFile, ifTester)); + } + return suite; } - } diff --git a/test/java/org/apache/fop/intermediate/LayoutIFTestSuite.java b/test/java/org/apache/fop/intermediate/LayoutIFTestSuite.java new file mode 100644 index 000000000..720556a6b --- /dev/null +++ b/test/java/org/apache/fop/intermediate/LayoutIFTestSuite.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.intermediate; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.Iterator; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.fop.layoutengine.LayoutEngineTestSuite; + +/** + * JUnit test suite for the intermediate format + */ +public final class LayoutIFTestSuite { + + private LayoutIFTestSuite() { + // This is a utility class + } + + /** + * @return the test suite with all the tests (one for each XML file) + * @throws IOException in case of an I/O problem + */ + public static Test suite() throws IOException { + TestSuite suite = new TestSuite(); + + Collection files = LayoutEngineTestSuite.getTestFiles(); + + Iterator i = files.iterator(); + while (i.hasNext()) { + File f = (File)i.next(); + addIFTestCase(suite, f); + } + + return suite; + } + + private static void addIFTestCase(TestSuite suite, + final File f) throws IOException { + suite.addTest(new IFParserTestCase(f)); + } + +} diff --git a/test/java/org/apache/fop/intermediate/TestAssistant.java b/test/java/org/apache/fop/intermediate/TestAssistant.java new file mode 100644 index 000000000..7fd08dc3d --- /dev/null +++ b/test/java/org/apache/fop/intermediate/TestAssistant.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.intermediate; + +import java.io.File; +import java.io.IOException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.apache.xpath.XPathAPI; +import org.apache.xpath.objects.XObject; + +import org.apache.fop.apps.FopFactory; + +/** + * Helper class for running FOP tests. + */ +public class TestAssistant { + + // configure fopFactory as desired + private FopFactory fopFactory = FopFactory.newInstance(); + private FopFactory fopFactoryWithBase14Kerning = FopFactory.newInstance(); + + private SAXTransformerFactory tfactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + private DocumentBuilderFactory domBuilderFactory; + + private Templates testcase2fo; + private Templates testcase2checks; + + /** + * Main constructor. + */ + public TestAssistant() { + fopFactory.getFontManager().setBase14KerningEnabled(false); + fopFactoryWithBase14Kerning.getFontManager().setBase14KerningEnabled(true); + domBuilderFactory = DocumentBuilderFactory.newInstance(); + domBuilderFactory.setNamespaceAware(true); + domBuilderFactory.setValidating(false); + } + + /** + * Returns the stylesheet for convert extracting the XSL-FO part from the test case. + * @return the stylesheet + * @throws TransformerConfigurationException if an error occurs loading the stylesheet + */ + public Templates getTestcase2FOStylesheet() throws TransformerConfigurationException { + if (testcase2fo == null) { + //Load and cache stylesheet + Source src = new StreamSource(new File("test/layoutengine/testcase2fo.xsl")); + testcase2fo = tfactory.newTemplates(src); + } + return testcase2fo; + } + + /** + * Returns the stylesheet for convert extracting the checks from the test case. + * @return the stylesheet + * @throws TransformerConfigurationException if an error occurs loading the stylesheet + */ + private Templates getTestcase2ChecksStylesheet() throws TransformerConfigurationException { + if (testcase2checks == null) { + //Load and cache stylesheet + Source src = new StreamSource(new File("test/layoutengine/testcase2checks.xsl")); + testcase2checks = tfactory.newTemplates(src); + } + return testcase2checks; + } + + /** + * Returns the element from the given XML file that encloses the tests. + * + * @param testFile a test case + * @return the parent element of the group(s) of checks + * @throws TransformerException if an error occurs while extracting the test element + */ + public Element getTestRoot(File testFile) throws TransformerException { + Transformer transformer = getTestcase2ChecksStylesheet().newTransformer(); + DOMResult res = new DOMResult(); + transformer.transform(new StreamSource(testFile), res); + Document doc = (Document) res.getNode(); + return doc.getDocumentElement(); + } + + public FopFactory getFopFactory(boolean base14KerningEnabled) { + FopFactory effFactory = (base14KerningEnabled ? fopFactoryWithBase14Kerning : fopFactory); + return effFactory; + } + + public FopFactory getFopFactory(Document testDoc) { + boolean base14KerningEnabled = isBase14KerningEnabled(testDoc); + FopFactory effFactory = getFopFactory(base14KerningEnabled); + + boolean strictValidation = isStrictValidation(testDoc); + effFactory.setStrictValidation(strictValidation); + + return effFactory; + } + + private boolean isBase14KerningEnabled(Document testDoc) { + try { + XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/base14kerning"); + String s = xo.str(); + return ("true".equalsIgnoreCase(s)); + } catch (TransformerException e) { + throw new RuntimeException("Error while evaluating XPath expression", e); + } + } + + private boolean isStrictValidation(Document testDoc) { + try { + XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/strict-validation"); + return !("false".equalsIgnoreCase(xo.str())); + } catch (TransformerException e) { + throw new RuntimeException("Error while evaluating XPath expression", e); + } + } + + /** + * Loads a test case into a DOM document. + * @param testFile the test file + * @return the loaded test case + * @throws IOException if an I/O error occurs loading the test case + */ + public Document loadTestCase(File testFile) + throws IOException { + try { + DocumentBuilder builder = domBuilderFactory.newDocumentBuilder(); + Document testDoc = builder.parse(testFile); + return testDoc; + } catch (Exception e) { + throw new IOException("Error while loading test case: " + e.getMessage()); + } + } + + /** + * Serialize the DOM for later inspection. + * @param doc the DOM document + * @param target target file + * @throws TransformerException if a problem occurs during serialization + */ + public void saveDOM(Document doc, File target) throws TransformerException { + Transformer transformer = getTransformerFactory().newTransformer(); + Source src = new DOMSource(doc); + Result res = new StreamResult(target); + transformer.transform(src, res); + } + + /** + * Returns the SAXTransformerFactory. + * @return the SAXTransformerFactory + */ + public SAXTransformerFactory getTransformerFactory() { + return tfactory; + } +} diff --git a/test/java/org/apache/fop/layoutengine/EvalCheck.java b/test/java/org/apache/fop/layoutengine/EvalCheck.java index 32d9e689b..8065512a7 100644 --- a/test/java/org/apache/fop/layoutengine/EvalCheck.java +++ b/test/java/org/apache/fop/layoutengine/EvalCheck.java @@ -41,16 +41,6 @@ public class EvalCheck implements LayoutEngineCheck, IFCheck { private double tolerance; private PrefixResolver prefixResolver; - /** - * Creates a new instance - * @param expected expected value - * @param xpath XPath statement that needs to be evaluated - */ - public EvalCheck(String expected, String xpath) { - this.expected = expected; - this.xpath = xpath; - } - /** * Creates a new instance from a DOM node. * @param node DOM node that defines this check diff --git a/test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java b/test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java index 155db2263..ca979efe5 100644 --- a/test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java +++ b/test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java @@ -19,10 +19,12 @@ package org.apache.fop.layoutengine; +import org.apache.fop.check.Check; + /** * Defines the interface for check operations. */ -public interface LayoutEngineCheck { +public interface LayoutEngineCheck extends Check { /** * Called to perform the check. diff --git a/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java b/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java new file mode 100644 index 000000000..bea54c5f8 --- /dev/null +++ b/test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +/* $Id$ */ + +package org.apache.fop.layoutengine; + +import org.w3c.dom.Element; + +import org.apache.fop.check.ChecksFactory; + +/** + * A factory class for creating {@link LayoutEngineCheck} instances. + */ +final class LayoutEngineChecksFactory extends ChecksFactory { + + LayoutEngineChecksFactory() { + registerCheckFactory("true", new CheckFactory() { + + public LayoutEngineCheck createCheck(Element element) { + return new TrueCheck(element); + } + + }); + registerCheckFactory("eval", new CheckFactory() { + + public LayoutEngineCheck createCheck(Element element) { + return new EvalCheck(element); + } + + }); + registerCheckFactory("element-list", new CheckFactory() { + + public LayoutEngineCheck createCheck(Element element) { + return new ElementListCheck(element); + } + + }); + registerCheckFactory("result", new CheckFactory() { + + public LayoutEngineCheck createCheck(Element element) { + return new ResultCheck(element); + } + + }); + } + +} diff --git a/test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java b/test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java index 32a48fb0b..397374657 100644 --- a/test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java +++ b/test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java @@ -56,12 +56,16 @@ import org.apache.fop.DebugHelper; /** * JUnit test suit for running layout engine test under JUnit control. */ -public class LayoutEngineTestSuite { +public final class LayoutEngineTestSuite { static { DebugHelper.registerStandardElementListObservers(); } + private LayoutEngineTestSuite() { + // This is a utility class + } + public static String[] readDisabledTestcases(File f) throws IOException { List lines = new java.util.ArrayList(); Source stylesheet = new StreamSource( @@ -178,45 +182,33 @@ public class LayoutEngineTestSuite { Iterator i = files.iterator(); while (i.hasNext()) { File f = (File)i.next(); - addTestCase(suite, tester, f); + suite.addTest(new LayoutEngineTestCase(f, tester)); } return suite; } - private static void addTestCase(TestSuite suite, - final LayoutEngineTester tester, final File f) { - suite.addTest(new LayoutEngineTestCase(f.getName()) { - public void runTest() throws Exception { - try { - prepare(tester, f); - testMain(); - } catch (Exception e) { - org.apache.commons.logging.LogFactory.getLog( - this.getClass()).error("Error on " + f.getName()); - throw e; - } - } - }); - } - private static class LayoutEngineTestCase extends TestCase { - private LayoutEngineTester tester; - private File testFile; + private final File testFile; - public LayoutEngineTestCase(String name) { - super(name); - } + private final LayoutEngineTester tester; - public void prepare(LayoutEngineTester tester, File testFile) { - //super(testFile.getName()); - this.tester = tester; + LayoutEngineTestCase(File testFile, LayoutEngineTester tester) { + super(testFile.getName()); this.testFile = testFile; + this.tester = tester; } - public void testMain() throws Exception { - tester.runTest(testFile); + @Override + protected void runTest() throws Throwable { + try { + tester.runTest(testFile); + } catch (Exception e) { + org.apache.commons.logging.LogFactory.getLog( + this.getClass()).error("Error on " + getName()); + throw e; + } } } } diff --git a/test/java/org/apache/fop/layoutengine/LayoutEngineTester.java b/test/java/org/apache/fop/layoutengine/LayoutEngineTester.java index 2c0cf8504..51c05a95f 100644 --- a/test/java/org/apache/fop/layoutengine/LayoutEngineTester.java +++ b/test/java/org/apache/fop/layoutengine/LayoutEngineTester.java @@ -21,37 +21,42 @@ package org.apache.fop.layoutengine; import java.io.File; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.util.Iterator; import java.util.List; -import java.util.Map; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.TransformerHandler; -import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.Node; import org.w3c.dom.NodeList; - +import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.FormattingResults; +import org.apache.fop.area.AreaTreeModel; +import org.apache.fop.area.AreaTreeParser; +import org.apache.fop.area.RenderPagesModel; import org.apache.fop.events.model.EventSeverity; +import org.apache.fop.fonts.FontInfo; import org.apache.fop.intermediate.IFTester; +import org.apache.fop.intermediate.TestAssistant; import org.apache.fop.layoutmgr.ElementListObserver; +import org.apache.fop.render.intermediate.IFContext; +import org.apache.fop.render.intermediate.IFRenderer; +import org.apache.fop.render.intermediate.IFSerializer; import org.apache.fop.render.xml.XMLRenderer; import org.apache.fop.util.ConsoleEventListenerForTests; +import org.apache.fop.util.DelegatingContentHandler; /** * Class for testing the FOP's layout engine using testcases specified in XML @@ -59,19 +64,13 @@ import org.apache.fop.util.ConsoleEventListenerForTests; */ public class LayoutEngineTester { - private static final Map AT_CHECK_CLASSES = new java.util.HashMap(); - - private TestEnvironment env = new TestEnvironment(); + private TestAssistant testAssistant = new TestAssistant(); + private LayoutEngineChecksFactory layoutEngineChecksFactory = new LayoutEngineChecksFactory(); private File areaTreeBackupDir; private IFTester ifTester; - static { - AT_CHECK_CLASSES.put("true", TrueCheck.class); - AT_CHECK_CLASSES.put("eval", EvalCheck.class); - AT_CHECK_CLASSES.put("element-list", ElementListCheck.class); - AT_CHECK_CLASSES.put("result", ResultCheck.class); - } + private TransformerFactory tfactory = TransformerFactory.newInstance(); /** * Constructs a new instance. @@ -80,7 +79,7 @@ public class LayoutEngineTester { */ public LayoutEngineTester(File areaTreeBackupDir) { this.areaTreeBackupDir = areaTreeBackupDir; - this.ifTester = new IFTester(areaTreeBackupDir); + this.ifTester = new IFTester(tfactory, areaTreeBackupDir); } /** @@ -100,18 +99,18 @@ public class LayoutEngineTester { ElementListObserver.addObserver(elCollector); Fop fop; - + FopFactory effFactory; try { - Document testDoc = env.loadTestCase(testFile); - FopFactory effFactory = env.getFopFactory(testDoc); + Document testDoc = testAssistant.loadTestCase(testFile); + effFactory = testAssistant.getFopFactory(testDoc); //Setup Transformer to convert the testcase XML to XSL-FO - Transformer transformer = env.getTestcase2FOStylesheet().newTransformer(); + Transformer transformer = testAssistant.getTestcase2FOStylesheet().newTransformer(); Source src = new DOMSource(testDoc); //Setup Transformer to convert the area tree to a DOM TransformerHandler athandler; - athandler = env.getTransformerFactory().newTransformerHandler(); + athandler = testAssistant.getTransformerFactory().newTransformerHandler(); athandler.setResult(domres); //Setup FOP for area tree rendering @@ -134,91 +133,96 @@ public class LayoutEngineTester { Document doc = (Document)domres.getNode(); if (this.areaTreeBackupDir != null) { - env.saveDOM(doc, + testAssistant.saveDOM(doc, new File(this.areaTreeBackupDir, testFile.getName() + ".at.xml")); } FormattingResults results = fop.getResults(); LayoutResult result = new LayoutResult(doc, elCollector, results); - checkAll(testFile, result); + checkAll(effFactory, testFile, result); } - /** - * Factory method to create AT checks from DOM elements. - * @param el DOM element to create the check from - * @return The newly create check - */ - protected LayoutEngineCheck createATCheck(Element el) { - String name = el.getTagName(); - Class clazz = (Class)AT_CHECK_CLASSES.get(name); - if (clazz != null) { - try { - Constructor c = clazz.getDeclaredConstructor(new Class[] {Node.class}); - LayoutEngineCheck instance = (LayoutEngineCheck)c.newInstance(new Object[] {el}); - return instance; - } catch (Exception e) { - throw new RuntimeException("Error while instantiating check '" - + name + "': " + e.getMessage()); - } - } else { - throw new IllegalArgumentException("No check class found: " + name); - } - } - - /** * Perform all checks on the area tree and, optionally, on the intermediate format. * @param testFile Test case XML file * @param result The layout results * @throws TransformerException if a problem occurs in XSLT/JAXP */ - protected void checkAll(File testFile, LayoutResult result) throws TransformerException { - Transformer transformer = env.getTestcase2ChecksStylesheet().newTransformer(); - Source src = new StreamSource(testFile); - DOMResult res = new DOMResult(); - transformer.transform(src, res); - - Document doc = (Document)res.getNode(); - Element root = doc.getDocumentElement(); + protected void checkAll(FopFactory fopFactory, File testFile, LayoutResult result) + throws TransformerException { + Element testRoot = testAssistant.getTestRoot(testFile); NodeList nodes; //AT tests only when checks are available - nodes = root.getElementsByTagName("at-checks"); + nodes = testRoot.getElementsByTagName("at-checks"); if (nodes.getLength() > 0) { Element atChecks = (Element)nodes.item(0); doATChecks(atChecks, result); } //IF tests only when checks are available - nodes = root.getElementsByTagName("if-checks"); + nodes = testRoot.getElementsByTagName("if-checks"); if (nodes.getLength() > 0) { Element ifChecks = (Element)nodes.item(0); - ifTester.doIFChecks(testFile, ifChecks, result.getAreaTree()); + Document ifDocument = createIF(fopFactory, testFile, result.getAreaTree()); + ifTester.doIFChecks(testFile.getName(), ifChecks, ifDocument); } } - private void doATChecks(Element checksRoot, LayoutResult result) { - //First create check before actually running them - List checks = new java.util.ArrayList(); - NodeList nodes = checksRoot.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node instanceof Element) { - checks.add(createATCheck((Element)node)); - } - } + private Document createIF(FopFactory fopFactory, File testFile, Document areaTreeXML) + throws TransformerException { + try { + FOUserAgent ua = fopFactory.newFOUserAgent(); + ua.setBaseURL(testFile.getParentFile().toURI().toURL().toExternalForm()); + ua.getEventBroadcaster().addEventListener( + new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN)); - if (checks.size() == 0) { - throw new RuntimeException("No checks are available!"); - } + IFRenderer ifRenderer = new IFRenderer(); + ifRenderer.setUserAgent(ua); + + IFSerializer serializer = new IFSerializer(); + serializer.setContext(new IFContext(ua)); + DOMResult result = new DOMResult(); + serializer.setResult(result); + ifRenderer.setDocumentHandler(serializer); + + ua.setRendererOverride(ifRenderer); + FontInfo fontInfo = new FontInfo(); + //Construct the AreaTreeModel that will received the individual pages + final AreaTreeModel treeModel = new RenderPagesModel(ua, + null, fontInfo, null); + + //Iterate over all intermediate files + AreaTreeParser parser = new AreaTreeParser(); + ContentHandler handler = parser.getContentHandler(treeModel, ua); + + DelegatingContentHandler proxy = new DelegatingContentHandler() { - //Run the actual tests now that we know that the checks themselves are ok - doATChecks(checks, result); + public void endDocument() throws SAXException { + super.endDocument(); + //Signal the end of the processing. + //The renderer can finalize the target document. + treeModel.endDocument(); + } + + }; + proxy.setDelegateContentHandler(handler); + + Transformer transformer = tfactory.newTransformer(); + transformer.transform(new DOMSource(areaTreeXML), new SAXResult(proxy)); + + return (Document)result.getNode(); + } catch (Exception e) { + throw new TransformerException( + "Error while generating intermediate format file: " + e.getMessage(), e); + } } - private void doATChecks(List checks, LayoutResult result) { - Iterator i = checks.iterator(); - while (i.hasNext()) { - LayoutEngineCheck check = (LayoutEngineCheck)i.next(); + private void doATChecks(Element checksRoot, LayoutResult result) { + List checks = layoutEngineChecksFactory.createCheckList(checksRoot); + if (checks.size() == 0) { + throw new RuntimeException("No available area tree check"); + } + for (LayoutEngineCheck check : checks) { check.check(result); } } diff --git a/test/java/org/apache/fop/layoutengine/ResultCheck.java b/test/java/org/apache/fop/layoutengine/ResultCheck.java index 54af77a43..ce95c5024 100644 --- a/test/java/org/apache/fop/layoutengine/ResultCheck.java +++ b/test/java/org/apache/fop/layoutengine/ResultCheck.java @@ -19,9 +19,10 @@ package org.apache.fop.layoutengine; -import org.apache.fop.apps.FormattingResults; import org.w3c.dom.Node; +import org.apache.fop.apps.FormattingResults; + /** * Simple check that requires a result property to evaluate to the expected value */ @@ -30,16 +31,6 @@ public class ResultCheck implements LayoutEngineCheck { private String expected; private String property; - /** - * Creates a new instance - * @param expected expected value - * @param property property of which the value needs to be evaluated - */ - public ResultCheck(String expected, String property) { - this.expected = expected; - this.property = property; - } - /** * Creates a new instance from a DOM node. * @param node DOM node that defines this check diff --git a/test/java/org/apache/fop/layoutengine/TestEnvironment.java b/test/java/org/apache/fop/layoutengine/TestEnvironment.java deleted file mode 100644 index ad976ff8c..000000000 --- a/test/java/org/apache/fop/layoutengine/TestEnvironment.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/* $Id$ */ - -package org.apache.fop.layoutengine; - -import java.io.File; -import java.io.IOException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.Document; - -import org.apache.xpath.XPathAPI; -import org.apache.xpath.objects.XObject; - -import org.apache.fop.apps.FopFactory; - -/** - * Test environment and helper code for running FOP tests. - */ -public class TestEnvironment { - - // configure fopFactory as desired - private FopFactory fopFactory = FopFactory.newInstance(); - private FopFactory fopFactoryWithBase14Kerning = FopFactory.newInstance(); - - private SAXTransformerFactory tfactory - = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); - - private DocumentBuilderFactory domBuilderFactory; - - private Templates testcase2fo; - private Templates testcase2checks; - - /** - * Main constructor. - */ - public TestEnvironment() { - fopFactory.getFontManager().setBase14KerningEnabled(false); - fopFactoryWithBase14Kerning.getFontManager().setBase14KerningEnabled(true); - domBuilderFactory = DocumentBuilderFactory.newInstance(); - domBuilderFactory.setNamespaceAware(true); - domBuilderFactory.setValidating(false); - } - - /** - * Returns the stylesheet for convert extracting the XSL-FO part from the test case. - * @return the stylesheet - * @throws TransformerConfigurationException if an error occurs loading the stylesheet - */ - public Templates getTestcase2FOStylesheet() throws TransformerConfigurationException { - if (testcase2fo == null) { - //Load and cache stylesheet - Source src = new StreamSource(new File("test/layoutengine/testcase2fo.xsl")); - testcase2fo = tfactory.newTemplates(src); - } - return testcase2fo; - } - - /** - * Returns the stylesheet for convert extracting the checks from the test case. - * @return the stylesheet - * @throws TransformerConfigurationException if an error occurs loading the stylesheet - */ - public Templates getTestcase2ChecksStylesheet() throws TransformerConfigurationException { - if (testcase2checks == null) { - //Load and cache stylesheet - Source src = new StreamSource(new File("test/layoutengine/testcase2checks.xsl")); - testcase2checks = tfactory.newTemplates(src); - } - return testcase2checks; - } - - public FopFactory getFopFactory(boolean base14KerningEnabled) { - FopFactory effFactory = (base14KerningEnabled ? fopFactoryWithBase14Kerning : fopFactory); - return effFactory; - } - - public FopFactory getFopFactory(Document testDoc) { - boolean base14KerningEnabled = isBase14KerningEnabled(testDoc); - FopFactory effFactory = getFopFactory(base14KerningEnabled); - - boolean strictValidation = isStrictValidation(testDoc); - effFactory.setStrictValidation(strictValidation); - - return effFactory; - } - - private boolean isBase14KerningEnabled(Document testDoc) { - try { - XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/base14kerning"); - String s = xo.str(); - return ("true".equalsIgnoreCase(s)); - } catch (TransformerException e) { - throw new RuntimeException("Error while evaluating XPath expression", e); - } - } - - private boolean isStrictValidation(Document testDoc) { - try { - XObject xo = XPathAPI.eval(testDoc, "/testcase/cfg/strict-validation"); - return !("false".equalsIgnoreCase(xo.str())); - } catch (TransformerException e) { - throw new RuntimeException("Error while evaluating XPath expression", e); - } - } - - /** - * Loads a test case into a DOM document. - * @param testFile the test file - * @return the loaded test case - * @throws IOException if an I/O error occurs loading the test case - */ - public Document loadTestCase(File testFile) - throws IOException { - try { - DocumentBuilder builder = domBuilderFactory.newDocumentBuilder(); - Document testDoc = builder.parse(testFile); - return testDoc; - } catch (Exception e) { - throw new IOException("Error while loading test case: " + e.getMessage()); - } - } - - /** - * Serialize the DOM for later inspection. - * @param doc the DOM document - * @param target target file - * @throws TransformerException if a problem occurs during serialization - */ - public void saveDOM(Document doc, File target) throws TransformerException { - Transformer transformer = getTransformerFactory().newTransformer(); - Source src = new DOMSource(doc); - Result res = new StreamResult(target); - transformer.transform(src, res); - } - - /** - * Returns the SAXTransformerFactory. - * @return the SAXTransformerFactory - */ - public SAXTransformerFactory getTransformerFactory() { - return tfactory; - } -} diff --git a/test/java/org/apache/fop/layoutengine/TrueCheck.java b/test/java/org/apache/fop/layoutengine/TrueCheck.java index 94ae942de..77d76b91d 100644 --- a/test/java/org/apache/fop/layoutengine/TrueCheck.java +++ b/test/java/org/apache/fop/layoutengine/TrueCheck.java @@ -41,14 +41,6 @@ public class TrueCheck implements LayoutEngineCheck, IFCheck { private String failureMessage; private PrefixResolver prefixResolver; - /** - * Creates a new instance - * @param xpath XPath statement that needs to be evaluated - */ - public TrueCheck(String xpath) { - this.xpath = xpath; - } - /** * Creates a new instance from a DOM node. * @param node DOM node that defines this check