testsuite="org.apache.fop.intermediate.AreaTreeXMLFormatTestSuite"
outfile="TEST-area-tree-xml-format"/>
</target>
- <target name="junit-intermediate-format" depends="junit-compile"
+ <target name="junit-intermediate-layout" depends="junit-compile" if="xmlunit.present">
+ <junit-run title="intermediate format from layout tests"
+ testsuite="org.apache.fop.intermediate.LayoutIFTestSuite"
+ outfile="TEST-intermediate-format-from-layout"/>
+ </target>
+ <target name="junit-intermediate-format" depends="junit-compile,junit-intermediate-layout"
description="Runs FOP's intermediate format JUnit tests" if="xmlunit.present">
<junit-run title="intermediate format"
testsuite="org.apache.fop.intermediate.IntermediateFormatTestSuite"
</xs:complexContent>
</xs:complexType>
</xs:element>
+ <xs:element name="id">
+ <xs:complexType>
+ <xs:attribute name="name" use="required" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
<xs:element name="font">
<xs:complexType>
<xs:attribute name="family" type="xs:string"/>
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";
}
private String structurePointer;
+ private String id = "";
+
/**
* Main constructor.
* @param ua the user agent
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;
+ }
+
}
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;
private static SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
- private static Set handledNamespaces = new java.util.HashSet();
+ private static Set<String> handledNamespaces = new java.util.HashSet<String>();
static {
handledNamespaces.add(XMLNS_NAMESPACE_URI);
private static class Handler extends DefaultHandler {
- private Map elementHandlers = new java.util.HashMap();
+ private Map<String, ElementHandler> elementHandlers = new HashMap<String, ElementHandler>();
private IFDocumentHandler documentHandler;
private IFPainter painter;
//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());
}
}
- private void establishForeignAttributes(Map foreignAttributes) {
+ private void establishForeignAttributes(Map<QName, String> foreignAttributes) {
documentHandler.getContext().setForeignAttributes(foreignAttributes);
}
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) {
}
} else {
if (NAMESPACE.equals(uri)) {
- ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
+ ElementHandler elementHandler = elementHandlers.get(localName);
if (elementHandler != null) {
try {
elementHandler.endElement();
documentHandler.getContext().setLanguage(
XMLUtil.convertRFC3066ToLocale(xmllang));
}
- Map foreignAttributes = getForeignAttributes(lastAttributes);
+ Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
documentHandler.startPageSequence(id);
resetForeignAttributes();
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<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
documentHandler.startPage(index, name, pageMasterName,
new Dimension(width, height));
public void endElement() throws IFException {
painter = null;
+ documentHandler.getContext().setID("");
documentHandler.endPageContent();
}
}
+ 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 {
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<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
setStructurePointer(lastAttributes);
if (foreignObject != null) {
}
}
- private static Map getForeignAttributes(Attributes atts) {
- Map foreignAttributes = null;
+ private static Map<QName, String> getForeignAttributes(Attributes atts) {
+ Map<QName, String> foreignAttributes = null;
for (int i = 0, c = atts.getLength(); i < c; i++) {
String ns = atts.getURI(i);
if (ns.length() > 0) {
continue;
}
if (foreignAttributes == null) {
- foreignAttributes = new java.util.HashMap();
+ foreignAttributes = new java.util.HashMap<QName, String>();
}
QName qname = new QName(ns, atts.getQName(i));
foreignAttributes.put(qname, atts.getValue(i));
private TextUtil textUtil = new TextUtil();
+ private Stack<String> ids = new Stack<String>();
+
/**
* Main constructor
*/
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} */
/** {@inheritDoc} */
protected void renderInlineArea(InlineArea inlineArea) {
saveInlinePosIfTargetable(inlineArea);
+ pushdID(inlineArea);
super.renderInlineArea(inlineArea);
+ popID(inlineArea);
}
/** {@inheritDoc} */
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) {
/** Holds the intermediate format state */
private IFState state;
+ private String currentID = "";
+
/**
* Default constructor.
*/
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);
/** {@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));
/** {@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));
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));
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));
}
}
- // ---=== 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();
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
+ <action context="Renderers" dev="VH" type="add">
+ Added id element to intermediate format to track the origin of content.
+ </action>
<action context="Renderers" dev="AD" type="fix" fixes-bug="50987" due-to="Matthias Reischenbacher">
Bugzilla 50988: Fixed a NullPointerException in case a white-space fo:character was removed
due to white-space handling.
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from a block-container properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block-container id="block-container" space-before="10pt" color="purple"
+ font-family="serif"><fo: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.</fo:block></fo:block-container>
+ <fo:block space-before="10pt">Proin varius egestas erat. Proin ante eros, consequat eget
+ semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <eval expected="8" xpath="count(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+
+ <eval expected="block-container" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][2]/@name"/>
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from a block-container properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block-container space-before="10pt" id="block-container_outer_1" color="purple">
+ <fo:block>In vel libero libero, a semper est. Vivamus dapibus ante id lorem mattis eget
+ mattis urna sodales.
+ <fo:block-container id="block-container_inner_1" color="blue" start-indent="2em">
+ <fo:block start-indent="0">Vestibulum nec dui urna, in porta mi. Proin varius egestas
+ erat. Donec pharetra iaculis dolor, ut rutrum nunc facilisis
+ at.</fo:block>
+ </fo:block-container>
+ Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel
+ leo luctus dapibus.</fo:block>
+ </fo:block-container>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ <fo:block-container space-before="10pt" color="purple" id="block-container_1">
+ <fo:block>Sed ultrices posuere posuere. Praesent vitae ligula odio.</fo:block>
+ </fo:block-container>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block-container space-before="10pt" id="block-container_outer_2" color="purple">
+ <fo:block>In vel libero libero, a semper est. Vivamus dapibus ante id lorem mattis eget
+ mattis urna sodales.
+ <fo:block color="black" start-indent="2em">Mauris tincidunt, risus eget vulputate elementum,
+ turpis lorem aliquet purus, eu sagittis neque sapien vel lectus.
+ <fo:block-container id="block-container_inner_2" color="blue">
+ <fo:block>Vestibulum nec dui urna, in porta mi. Proin varius egestas erat. Donec
+ pharetra iaculis dolor, ut rutrum nunc facilisis at.</fo:block>
+ </fo:block-container>
+ Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel
+ leo luctus dapibus.</fo:block>
+ Vivamus ut sollicitudin metus. Curabitur sit amet aliquam
+ enim.</fo:block>
+ </fo:block-container>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ <fo:block-container space-before="10pt" color="purple" id="block-container_2">
+ <fo:block>Vivamus tellus libero, porttitor a lacinia a, tempor eu dui. Pellentesque
+ fermentum odio tempor lorem interdum pharetra.</fo:block>
+ </fo:block-container>
+ <fo:block space-before="10pt">Donec auctor venenatis convallis.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <!-- Page 1 -->
+ <eval expected="16" xpath="count(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+
+ <eval expected="block-container_outer_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="block-container_inner_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="block-container_outer_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="block-container_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][5]/@name"/>
+
+ <!-- Page 2 -->
+ <eval expected="22" xpath="count(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][17])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][18])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][19])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][20])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][21])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][22])"/>
+
+ <eval expected="block-container_outer_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="block-container_inner_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="block-container_outer_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="block-container_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][5]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][6]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from a block properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block id="block" space-before="10pt" color="purple" font-family="serif">In vel libero
+ libero, a semper est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales.
+ Vestibulum nec dui urna, in porta mi.</fo:block>
+ <fo:block space-before="10pt">Proin varius egestas erat. Proin ante eros, consequat eget
+ semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <eval expected="8" xpath="count(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+
+ <eval expected="block" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][2]/@name"/>
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from a block properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block space-before="10pt" id="outer-block_1" color="purple">In vel libero libero, a semper
+ est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales.
+ <fo:block id="inner-block_1" color="blue" start-indent="2em">Vestibulum nec dui urna, in
+ porta mi. Proin varius egestas erat. Donec pharetra iaculis dolor, ut rutrum nunc
+ facilisis at.</fo:block>
+ Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel
+ leo luctus dapibus.</fo:block>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ <fo:block space-before="10pt" color="purple" id="block_1">Sed ultrices posuere posuere.
+ Praesent vitae ligula odio.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:block space-before="10pt" id="outer-block_2" color="purple">In vel libero libero, a semper
+ est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales.
+ <fo:block color="black" start-indent="2em">Mauris tincidunt, risus eget vulputate elementum,
+ turpis lorem aliquet purus, eu sagittis neque sapien vel lectus.
+ <fo:block id="inner-block_2" color="blue" start-indent="4em">Vestibulum nec dui urna, in
+ porta mi. Proin varius egestas erat. Donec pharetra iaculis dolor, ut rutrum nunc
+ facilisis at.</fo:block>
+ Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel
+ leo luctus dapibus.</fo:block>
+ Vivamus ut sollicitudin metus. Curabitur sit amet aliquam enim.</fo:block>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ <fo:block space-before="10pt" color="purple" id="block_2">Vivamus tellus libero, porttitor a
+ lacinia a, tempor eu dui. Pellentesque fermentum odio tempor lorem interdum
+ pharetra.</fo:block>
+ <fo:block space-before="10pt">Donec auctor venenatis convallis.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <!-- Page 1 -->
+ <eval expected="16" xpath="count(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+
+ <eval expected="outer-block_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="inner-block_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="outer-block_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="block_1" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][5]/@name"/>
+
+ <!-- Page 2 -->
+ <eval expected="22" xpath="count(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][17])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][18])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][19])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][20])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][21])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][22])"/>
+
+ <eval expected="outer-block_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="inner-block_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="outer-block_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="block_2" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][5]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][6]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from a block that spans over different pages properly appear
+ in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="120pt" page-width="270pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor.</fo:block>
+ <fo:block space-before="60pt" id="block" color="purple">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.</fo:block>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor.</fo:block>
+ <fo:block space-before="40pt" id="outer-block" color="purple">In vel libero libero, a semper
+ est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales.
+ <fo:block id="inner-block" color="blue" start-indent="2em">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.</fo:block>
+ Proin ante eros, consequat eget semper a, molestie non arcu. Praesent hendrerit dolor vel
+ leo luctus dapibus.</fo:block>
+ <fo:block space-before="10pt">Nullam quam nisl, iaculis ut fermentum et, vestibulum id elit.
+ Suspendisse fermentum fermentum ullamcorper.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <!-- Page-sequence 1 Page 1 -->
+ <eval expected="5" xpath="count(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+
+ <eval expected="block" xpath="//if:page-sequence[1]/if:page[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+
+ <!-- Page-sequence 1 Page 2 -->
+ <eval expected="6" xpath="count(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+
+ <eval expected="block" xpath="//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[1]/if:page[2]/descendant::*[local-name() = 'id'][2]/@name"/>
+
+
+ <!-- Page-sequence 2 Page 1 -->
+ <eval expected="8" xpath="count(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+
+ <eval expected="outer-block" xpath="//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="inner-block" xpath="//if:page-sequence[2]/if:page[1]/descendant::*[local-name() = 'id'][2]/@name"/>
+
+ <!-- Page-sequence 2 Page 2 -->
+ <eval expected="9" xpath="count(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+
+ <eval expected="inner-block" xpath="//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="outer-block" xpath="//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/if:page[2]/descendant::*[local-name() = 'id'][3]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from images properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. <fo:external-graphic src="../resources/images/fop-logo-color-24bit.png"
+ id="external-graphic"/>Vivamus porttitor sollicitudin tortor eu vulputate. In vel
+ libero libero, a semper est.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. <fo:instream-foreign-object id="instream-foreign-object" width="120pt"
+ display-align="center" content-width="scale-to-fit">
+ <svg xmlns="http://www.w3.org/2000/svg" width="300" height="286.6">
+ <g style="fill-opacity:0.7; stroke:black; stroke-width:3"
+ transform="translate(0, 286.6) scale(1, -1) translate(100, 100)">
+ <circle cx="50" cy="86.6" r="80" style="fill:red;"/>
+ <circle cx="0" cy="0" r="80" style="fill:green;"/>
+ <circle cx="100" cy="0" r="80" style="fill:blue;"/>
+ </g>
+ </svg>
+ </fo:instream-foreign-object> Vivamus porttitor sollicitudin tortor eu vulputate. In vel
+ libero libero, a semper est.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <!-- Page 1 -->
+ <eval expected="7" xpath="count(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][3])"/>
+ <eval expected="image" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][4])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[1]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][7])"/>
+
+ <eval expected="external-graphic" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[1]/descendant::*[local-name() = 'id'][2]/@name"/>
+
+ <!-- Page 2 -->
+ <eval expected="7" xpath="count(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][3])"/>
+ <eval expected="image" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][4])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence[2]/descendant::*[local-name() = 'text' or local-name() = 'image' or local-name() = 'id'][7])"/>
+
+ <eval expected="instream-foreign-object" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page-sequence[2]/descendant::*[local-name() = 'id'][2]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from various inline elements properly appear in the IF
+ output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page" id="page-sequence">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block font-family="sans-serif">Lorem ipsum dolor sit amet, <fo:character id="character"
+ font-size="150%" font-weight="bold" color="purple" character="C"/>onsectetur adipiscing
+ elit. <fo:inline id="inline" color="purple" font-family="serif">Fusce rutrum leo a diam
+ bibendum auctor.</fo:inline> Vivamus porttitor sollicitudin tortor eu vulputate. In vel
+ libero libero, a semper est. Vivamus<fo:leader id="leader" leader-length="50pt"
+ leader-pattern="rule" color="purple"/> dapibus ante id lorem mattis eget mattis urna
+ sodales. This is page number <fo:page-number id="page-number" color="purple"/>. Vestibulum
+ nec dui urna, in porta mi. The fo:character object is on page <fo:page-number-citation
+ id="page-number-citation" ref-id="character" color="purple"/>. Proin varius egestas erat.
+ Proin ante eros, consequat eget semper a, molestie non arcu. The last page of this document
+ is page <fo:page-number-citation-last id="page-number-citation-last" ref-id="page-sequence"
+ color="purple"/>. Praesent hendrerit dolor vel leo luctus dapibus.</fo:block>
+
+ <fo:block break-before="page">Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <eval expected="32" xpath="count(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][1])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][2])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][3])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][7])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][8])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][10])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][11])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][12])"/>
+ <eval expected="line" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][13])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][14])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][15])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][16])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][17])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][18])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][19])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][20])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][21])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][22])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][23])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][24])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][25])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][26])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][27])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][28])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][29])"/>
+ <eval expected="id" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][30])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][31])"/>
+ <eval expected="text" xpath="local-name(//if:page[1]/descendant::*[local-name() = 'text' or local-name() = 'line' or local-name() = 'id'][32])"/>
+
+ <eval expected="character" xpath="//if:page[1]/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="inline" xpath="//if:page[1]/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="leader" xpath="//if:page[1]/descendant::*[local-name() = 'id'][5]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][6]/@name"/>
+ <eval expected="page-number" xpath="//if:page[1]/descendant::*[local-name() = 'id'][7]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][8]/@name"/>
+ <eval expected="page-number-citation" xpath="//if:page[1]/descendant::*[local-name() = 'id'][9]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][10]/@name"/>
+ <eval expected="page-number-citation-last" xpath="//if:page[1]/descendant::*[local-name() = 'id'][11]/@name"/>
+ <eval expected="" xpath="//if:page[1]/descendant::*[local-name() = 'id'][12]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from the various elements of a list properly appear in the IF
+ output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:list-block provisional-distance-between-starts="10pt" provisional-label-separation="5pt"
+ id="list-block" space-before="10pt">
+ <fo:list-item id="list-item_1">
+ <fo:list-item-label end-indent="label-end()" id="list-item-label">
+ <fo:block>•</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()" id="list-item-body">
+ <fo:block>Item 1</fo:block>
+ <fo:block>id="list-item-body"</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item id="list-item_2" space-before="5pt">
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block>•</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()">
+ <fo:block>Item 2</fo:block>
+ <fo:block>id="list-item_2"</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item space-before="5pt">
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block>•</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()">
+ <fo:block>Item 3</fo:block>
+ <fo:block>id="list-block"</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </fo:list-block>
+ <fo:block id="block" space-before="10pt" color="purple" font-family="serif">In vel libero
+ libero, a semper est. Vivamus dapibus ante id lorem mattis eget mattis urna sodales.
+ Vestibulum nec dui urna, in porta mi.</fo:block>
+ <fo:block space-before="10pt">Proin varius egestas erat. Proin ante eros, consequat eget
+ semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <eval expected="21" xpath="count(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][17])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][18])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][19])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][20])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][21])"/>
+
+ <eval expected="list-item-label" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="list-item-body" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="list-item_2" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="list-block" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="block" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][5]/@name"/>
+ <eval expected="" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][6]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ 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.
+-->
+<testcase>
+ <info>
+ <p>
+ This test checks that IDs coming from the various elements of a table properly appear in the IF output.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="320pt" page-width="420pt" margin="10pt">
+ <fo:region-body/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce rutrum leo a diam
+ bibendum auctor. Vivamus porttitor sollicitudin tortor eu vulputate.</fo:block>
+ <fo:table id="table"
+ table-layout="fixed"
+ border-collapse="separate"
+ space-before="10pt"
+ start-indent="10%"
+ width="80%"
+ border="4pt solid purple"
+ border-separation="2pt"
+ padding="1pt"
+ font-size="10pt">
+ <fo:table-header id="table-header" start-indent="0">
+ <fo:table-cell border="2pt solid black" padding="2pt" id="table-cell_header_1.1">
+ <fo:block>Header 1.1</fo:block>
+ <fo:block>id="table-cell_header_1.1"</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="2pt solid black" padding="2pt">
+ <fo:block>Header 1.2 id="table-header"</fo:block>
+ </fo:table-cell>
+ </fo:table-header>
+ <fo:table-body id="table-body_1" start-indent="0">
+ <fo:table-row id="table-row_1">
+ <fo:table-cell border="1pt solid black" padding="2pt" id="table-cell_1.1">
+ <fo:block>Cell 1.1 id="table-cell_1.1"</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block>Cell 1.2 id="table-row_1"</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block>Cell 2.1 id="table-body_1"</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block>Cell 2.2 id="table-body_1"</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ <fo:table-body start-indent="0">
+ <fo:table-row id="table-row_3">
+ <fo:table-cell border="1pt solid black" padding="2pt" id="table-cell_3.1">
+ <fo:block>Cell 3.1 id="table-cell_3.1"</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block>Cell 3.2 id="table-row_3"</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block id="block">Cell 4.1 id="block"</fo:block>
+ </fo:table-cell>
+ <fo:table-cell border="1pt solid black" padding="2pt">
+ <fo:block>Cell 4.2 id="table"</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block space-before="10pt">Proin varius egestas erat. Proin ante eros, consequat eget
+ semper a, molestie non arcu. Praesent hendrerit dolor vel leo luctus dapibus.</fo:block>
+ <fo:block space-before="10pt" color="purple" id="block_outer">Mauris ac erat est, sit amet
+ dignissim elit. Ut pulvinar diam ut lorem pellentesque tempus.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+ </fo:root>
+ </fo>
+ <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+
+ <eval expected="27" xpath="count(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'])"/>
+
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][1])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][2])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][3])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][4])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][5])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][6])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][7])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][8])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][9])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][10])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][11])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][12])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][13])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][14])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][15])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][16])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][17])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][18])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][19])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][20])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][21])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][22])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][23])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][24])"/>
+ <eval expected="id" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][25])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][26])"/>
+ <eval expected="text" xpath="local-name(//if:page-sequence/descendant::*[local-name() = 'text' or local-name() = 'id'][27])"/>
+
+ <eval expected="table-cell_header_1.1" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][1]/@name"/>
+ <eval expected="table" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][2]/@name"/>
+ <eval expected="table-cell_1.1" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][3]/@name"/>
+ <eval expected="table" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][4]/@name"/>
+ <eval expected="table-cell_3.1" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][5]/@name"/>
+ <eval expected="table" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][6]/@name"/>
+ <eval expected="block" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][7]/@name"/>
+ <eval expected="table" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][8]/@name"/>
+ <eval expected="" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][9]/@name"/>
+ <eval expected="block_outer" xpath="//if:page-sequence/descendant::*[local-name() = 'id'][10]/@name"/>
+
+ </if-checks>
+</testcase>
--- /dev/null
+/*
+ * 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 {
+
+}
--- /dev/null
+/*
+ * 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 <C> a family of checks
+ */
+public abstract class ChecksFactory<C extends Check> {
+
+ /**
+ * A factory to create a particular kind of check.
+ */
+ protected static interface CheckFactory<C> {
+
+ /**
+ * 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<String, CheckFactory<C>> checkFactories
+ = new HashMap<String, CheckFactory<C>>();
+
+ /** 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<C> 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<C> factory = checkFactories.get(name);
+ if (factory == null) {
+ throw new IllegalArgumentException("No check class found for " + name);
+ } else {
+ return factory.createCheck(element);
+ }
+ }
+
+ public final List<C> createCheckList(Element container) {
+ List<C> checks = new ArrayList<C>();
+ 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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));
+ }
+
+}
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;
/**
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;
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()));
}
}
userAgent.getEventBroadcaster().addEventListener(
new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.FATAL));
} catch (MalformedURLException e) {
- //ignore, won't happen
+ // Shouldn't happen
+ throw new AssertionError();
}
return userAgent;
}
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);
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);
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();
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.
--- /dev/null
+/*
+ * 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<IFCheck> {
+
+ IFChecksFactory() {
+ registerCheckFactory("true", new CheckFactory<IFCheck>() {
+
+ public IFCheck createCheck(Element element) {
+ return new TrueCheck(element);
+ }
+
+ });
+ registerCheckFactory("eval", new CheckFactory<IFCheck>() {
+
+ public IFCheck createCheck(Element element) {
+ return new EvalCheck(element);
+ }
+
+ });
+ }
+}
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.
}
/** {@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();
}
/** {@inheritDoc} */
+ @Override
protected Document parseAndRenderToIntermediateFormat(Source src) throws Exception {
IFParser parser = new IFParser();
return (Document)domResult.getNode();
}
+ /** {@inheritDoc} */
+ @Override
+ public void runTest() throws Exception {
+ testParserToIntermediateFormat();
+ testParserToPDF();
+ }
+
}
--- /dev/null
+/*
+ * 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");
+ }
+
+}
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<IFCheck> 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);
}
}
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;
}
-
}
--- /dev/null
+/*
+ * 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));
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
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
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.
--- /dev/null
+/*
+ * 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<LayoutEngineCheck> {
+
+ LayoutEngineChecksFactory() {
+ registerCheckFactory("true", new CheckFactory<LayoutEngineCheck>() {
+
+ public LayoutEngineCheck createCheck(Element element) {
+ return new TrueCheck(element);
+ }
+
+ });
+ registerCheckFactory("eval", new CheckFactory<LayoutEngineCheck>() {
+
+ public LayoutEngineCheck createCheck(Element element) {
+ return new EvalCheck(element);
+ }
+
+ });
+ registerCheckFactory("element-list", new CheckFactory<LayoutEngineCheck>() {
+
+ public LayoutEngineCheck createCheck(Element element) {
+ return new ElementListCheck(element);
+ }
+
+ });
+ registerCheckFactory("result", new CheckFactory<LayoutEngineCheck>() {
+
+ public LayoutEngineCheck createCheck(Element element) {
+ return new ResultCheck(element);
+ }
+
+ });
+ }
+
+}
/**
* 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(
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;
+ }
}
}
}
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
*/
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.
*/
public LayoutEngineTester(File areaTreeBackupDir) {
this.areaTreeBackupDir = areaTreeBackupDir;
- this.ifTester = new IFTester(areaTreeBackupDir);
+ this.ifTester = new IFTester(tfactory, areaTreeBackupDir);
}
/**
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
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<LayoutEngineCheck> checks = layoutEngineChecksFactory.createCheckList(checksRoot);
+ if (checks.size() == 0) {
+ throw new RuntimeException("No available area tree check");
+ }
+ for (LayoutEngineCheck check : checks) {
check.check(result);
}
}
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
*/
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
+++ /dev/null
-/*
- * 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;
- }
-}
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