Browse Source

Added id element to intermediate format to track the origin of content.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1094690 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Vincent Hennebert 13 years ago
parent
commit
427df0fa7d
38 changed files with 1831 additions and 439 deletions
  1. 6
    1
      build.xml
  2. 5
    0
      src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd
  3. 2
    0
      src/java/org/apache/fop/render/intermediate/IFConstants.java
  4. 21
    0
      src/java/org/apache/fop/render/intermediate/IFContext.java
  5. 24
    11
      src/java/org/apache/fop/render/intermediate/IFParser.java
  6. 24
    0
      src/java/org/apache/fop/render/intermediate/IFRenderer.java
  7. 17
    1
      src/java/org/apache/fop/render/intermediate/IFSerializer.java
  8. 3
    0
      status.xml
  9. 64
    0
      test/intermediate/block-container.xml
  10. 148
    0
      test/intermediate/block-container_nested.xml
  11. 63
    0
      test/intermediate/block.xml
  12. 138
    0
      test/intermediate/block_nested.xml
  13. 126
    0
      test/intermediate/block_span_pages.xml
  14. 93
    0
      test/intermediate/images.xml
  15. 107
    0
      test/intermediate/inlines.xml
  16. 112
    0
      test/intermediate/list.xml
  17. 146
    0
      test/intermediate/table.xml
  18. 27
    0
      test/java/org/apache/fop/check/Check.java
  19. 97
    0
      test/java/org/apache/fop/check/ChecksFactory.java
  20. 25
    0
      test/java/org/apache/fop/check/package-info.java
  21. 137
    0
      test/java/org/apache/fop/intermediate/AbstractIFTestCase.java
  22. 9
    11
      test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java
  23. 2
    2
      test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java
  24. 3
    1
      test/java/org/apache/fop/intermediate/IFCheck.java
  25. 49
    0
      test/java/org/apache/fop/intermediate/IFChecksFactory.java
  26. 10
    107
      test/java/org/apache/fop/intermediate/IFParserTestCase.java
  27. 77
    0
      test/java/org/apache/fop/intermediate/IFTestCase.java
  28. 17
    136
      test/java/org/apache/fop/intermediate/IFTester.java
  29. 26
    30
      test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java
  30. 64
    0
      test/java/org/apache/fop/intermediate/LayoutIFTestSuite.java
  31. 22
    5
      test/java/org/apache/fop/intermediate/TestAssistant.java
  32. 0
    10
      test/java/org/apache/fop/layoutengine/EvalCheck.java
  33. 3
    1
      test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java
  34. 62
    0
      test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java
  35. 20
    28
      test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java
  36. 80
    76
      test/java/org/apache/fop/layoutengine/LayoutEngineTester.java
  37. 2
    11
      test/java/org/apache/fop/layoutengine/ResultCheck.java
  38. 0
    8
      test/java/org/apache/fop/layoutengine/TrueCheck.java

+ 6
- 1
build.xml View File

@@ -927,7 +927,12 @@ list of possible build targets.
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"

+ 5
- 0
src/documentation/intermediate-format-ng/fop-intermediate-format-ng-content.xsd View File

@@ -42,6 +42,11 @@
</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"/>

+ 2
- 0
src/java/org/apache/fop/render/intermediate/IFConstants.java View File

@@ -67,6 +67,8 @@ public interface IFConstants extends XMLConstants {
String EL_FONT = "font";
/** element name text */
String EL_TEXT = "text";
/** element name id */
String EL_ID = "id";
/** Parent element of the logical structure tree. */
String EL_STRUCTURE_TREE = "structure-tree";
}

+ 21
- 0
src/java/org/apache/fop/render/intermediate/IFContext.java View File

@@ -48,6 +48,8 @@ public class IFContext {

private String structurePointer;

private String id = "";

/**
* Main constructor.
* @param ua the user agent
@@ -155,4 +157,23 @@ public class IFContext {
return this.structurePointer;
}

/**
* Sets the ID of the object enclosing the content that will follow.
*
* @param id the ID of the nearest ancestor object for which the id property was set
*/
void setID(String id) {
assert id != null;
this.id = id;
}

/**
* Returns the ID of the object enclosing the current content.
*
* @return the ID of the nearest ancestor object for which the id property was set
*/
String getID() {
return id;
}

}

+ 24
- 11
src/java/org/apache/fop/render/intermediate/IFParser.java View File

@@ -24,6 +24,7 @@ import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@@ -76,7 +77,7 @@ public class IFParser implements IFConstants {
private static SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();

private static Set handledNamespaces = new java.util.HashSet();
private static Set<String> handledNamespaces = new java.util.HashSet<String>();

static {
handledNamespaces.add(XMLNS_NAMESPACE_URI);
@@ -132,7 +133,7 @@ public class IFParser implements IFConstants {

private static class Handler extends DefaultHandler {

private Map elementHandlers = new java.util.HashMap();
private Map<String, ElementHandler> elementHandlers = new HashMap<String, ElementHandler>();

private IFDocumentHandler documentHandler;
private IFPainter painter;
@@ -188,6 +189,7 @@ public class IFParser implements IFConstants {
//Page content
elementHandlers.put(EL_VIEWPORT, new ViewportHandler());
elementHandlers.put(EL_GROUP, new GroupHandler());
elementHandlers.put(EL_ID, new IDHandler());
elementHandlers.put(EL_FONT, new FontHandler());
elementHandlers.put(EL_TEXT, new TextHandler());
elementHandlers.put(EL_CLIP_RECT, new ClipRectHandler());
@@ -202,7 +204,7 @@ public class IFParser implements IFConstants {
}
}

private void establishForeignAttributes(Map foreignAttributes) {
private void establishForeignAttributes(Map<QName, String> foreignAttributes) {
documentHandler.getContext().setForeignAttributes(foreignAttributes);
}

@@ -300,7 +302,7 @@ public class IFParser implements IFConstants {
private boolean startIFElement(String localName, Attributes attributes)
throws SAXException {
lastAttributes = new AttributesImpl(attributes);
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
ElementHandler elementHandler = elementHandlers.get(localName);
content.setLength(0);
ignoreCharacters = true;
if (elementHandler != null) {
@@ -346,7 +348,7 @@ public class IFParser implements IFConstants {
}
} else {
if (NAMESPACE.equals(uri)) {
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName);
ElementHandler elementHandler = elementHandlers.get(localName);
if (elementHandler != null) {
try {
elementHandler.endElement();
@@ -432,7 +434,7 @@ public class IFParser implements IFConstants {
documentHandler.getContext().setLanguage(
XMLUtil.convertRFC3066ToLocale(xmllang));
}
Map foreignAttributes = getForeignAttributes(lastAttributes);
Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
documentHandler.startPageSequence(id);
resetForeignAttributes();
@@ -453,7 +455,7 @@ public class IFParser implements IFConstants {
String pageMasterName = attributes.getValue("page-master-name");
int width = Integer.parseInt(attributes.getValue("width"));
int height = Integer.parseInt(attributes.getValue("height"));
Map foreignAttributes = getForeignAttributes(lastAttributes);
Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
documentHandler.startPage(index, name, pageMasterName,
new Dimension(width, height));
@@ -486,6 +488,7 @@ public class IFParser implements IFConstants {

public void endElement() throws IFException {
painter = null;
documentHandler.getContext().setID("");
documentHandler.endPageContent();
}

@@ -536,6 +539,16 @@ public class IFParser implements IFConstants {

}

private class IDHandler extends AbstractElementHandler {

@Override
public void startElement(Attributes attributes) throws IFException, SAXException {
String id = attributes.getValue("name");
documentHandler.getContext().setID(id);
}

}

private class FontHandler extends AbstractElementHandler {

public void startElement(Attributes attributes) throws IFException {
@@ -660,7 +673,7 @@ public class IFParser implements IFConstants {
int y = Integer.parseInt(lastAttributes.getValue("y"));
int width = Integer.parseInt(lastAttributes.getValue("width"));
int height = Integer.parseInt(lastAttributes.getValue("height"));
Map foreignAttributes = getForeignAttributes(lastAttributes);
Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
setStructurePointer(lastAttributes);
if (foreignObject != null) {
@@ -712,8 +725,8 @@ public class IFParser implements IFConstants {
}
}

private static Map getForeignAttributes(Attributes atts) {
Map foreignAttributes = null;
private static Map<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) {
@@ -721,7 +734,7 @@ public class IFParser implements IFConstants {
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));

+ 24
- 0
src/java/org/apache/fop/render/intermediate/IFRenderer.java View File

@@ -153,6 +153,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

private TextUtil textUtil = new TextUtil();

private Stack<String> ids = new Stack<String>();

/**
* Main constructor
*/
@@ -841,11 +843,13 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
public void renderInlineViewport(InlineViewport viewport) {
String ptr = (String) viewport.getTrait(Trait.PTR);
establishStructurePointer(ptr);
pushdID(viewport);
Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD());
viewportDimensionStack.push(dim);
super.renderInlineViewport(viewport);
viewportDimensionStack.pop();
resetStructurePointer();
popID(viewport);
}

/** {@inheritDoc} */
@@ -888,7 +892,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
/** {@inheritDoc} */
protected void renderInlineArea(InlineArea inlineArea) {
saveInlinePosIfTargetable(inlineArea);
pushdID(inlineArea);
super.renderInlineArea(inlineArea);
popID(inlineArea);
}

/** {@inheritDoc} */
@@ -952,7 +958,25 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
log.trace("renderBlock() " + block);
}
saveBlockPosIfTargetable(block);
pushdID(block);
super.renderBlock(block);
popID(block);
}

private void pushdID(Area area) {
String prodID = (String) area.getTrait(Trait.PROD_ID);
if (prodID != null) {
ids.push(prodID);
documentHandler.getContext().setID(prodID);
}
}

private void popID(Area area) {
String prodID = (String) area.getTrait(Trait.PROD_ID);
if (prodID != null) {
ids.pop();
documentHandler.getContext().setID(ids.empty() ? "" : ids.peek());
}
}

private Typeface getTypeface(String fontName) {

+ 17
- 1
src/java/org/apache/fop/render/intermediate/IFSerializer.java View File

@@ -69,6 +69,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
/** Holds the intermediate format state */
private IFState state;

private String currentID = "";

/**
* Default constructor.
*/
@@ -306,6 +308,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
public void endPageContent() throws IFException {
try {
this.state = null;
currentID = "";
handler.endElement(EL_PAGE_CONTENT);
} catch (SAXException e) {
throw new IFException("SAX error in endPageContent()", e);
@@ -417,6 +420,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect) throws IFException {
try {
addID();
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, XLINK_HREF, uri);
addAttribute(atts, "x", Integer.toString(rect.x));
@@ -445,6 +449,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
/** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect) throws IFException {
try {
addID();
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, "x", Integer.toString(rect.x));
addAttribute(atts, "y", Integer.toString(rect.y));
@@ -534,6 +539,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
throws IFException {
try {
addID();
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, "x1", Integer.toString(start.x));
addAttribute(atts, "y1", Integer.toString(start.y));
@@ -552,6 +558,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
public void drawText(int x, int y, int letterSpacing, int wordSpacing,
int[] dx, String text) throws IFException {
try {
addID();
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, "x", Integer.toString(x));
addAttribute(atts, "y", Integer.toString(y));
@@ -671,7 +678,16 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
}
}

// ---=== IFDocumentNavigationHandler ===---
private void addID() throws SAXException {
String id = getContext().getID();
if (!currentID.equals(id)) {
AttributesImpl atts = new AttributesImpl();
addAttribute(atts, "name", id);
handler.startElement(EL_ID, atts);
handler.endElement(EL_ID);
currentID = id;
}
}

private Map incompleteActions = new java.util.HashMap();
private List completeActions = new java.util.LinkedList();

+ 3
- 0
status.xml View File

@@ -59,6 +59,9 @@
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.

+ 64
- 0
test/intermediate/block-container.xml View File

@@ -0,0 +1,64 @@
<?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>

+ 148
- 0
test/intermediate/block-container_nested.xml View File

@@ -0,0 +1,148 @@
<?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>

+ 63
- 0
test/intermediate/block.xml View File

@@ -0,0 +1,63 @@
<?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>

+ 138
- 0
test/intermediate/block_nested.xml View File

@@ -0,0 +1,138 @@
<?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>

+ 126
- 0
test/intermediate/block_span_pages.xml View File

@@ -0,0 +1,126 @@
<?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>

+ 93
- 0
test/intermediate/images.xml View File

@@ -0,0 +1,93 @@
<?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>

+ 107
- 0
test/intermediate/inlines.xml View File

@@ -0,0 +1,107 @@
<?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>

+ 112
- 0
test/intermediate/list.xml View File

@@ -0,0 +1,112 @@
<?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>

+ 146
- 0
test/intermediate/table.xml View File

@@ -0,0 +1,146 @@
<?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>

+ 27
- 0
test/java/org/apache/fop/check/Check.java View File

@@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.check;

/**
* A marker interface to identify checks in XML test cases.
*/
public interface Check {

}

+ 97
- 0
test/java/org/apache/fop/check/ChecksFactory.java View File

@@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.check;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
* A factory class for creating checks that belong to a same family.
* @param <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;
}
}

+ 25
- 0
test/java/org/apache/fop/check/package-info.java View File

@@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

/**
* A framework for creating checks from elements stored in an XML test case. The test case
* typically contains the XML document under test, along with a series of checks expressed
* as XML elements.
*/
package org.apache.fop.check;

+ 137
- 0
test/java/org/apache/fop/intermediate/AbstractIFTestCase.java View File

@@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.intermediate;

import java.io.File;
import java.io.IOException;

import javax.xml.XMLConstants;
import javax.xml.transform.Result;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFSerializer;

/**
* A common super-class for intermediate format test cases.
*/
abstract class AbstractIFTestCase extends AbstractIntermediateTestCase {

private static final Schema IF_SCHEMA;

static {
Schema ifSchema = null;
try {
SchemaFactory sFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
File ifSchemaFile = new File(
"src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd");
ifSchema = sFactory.newSchema(ifSchemaFile);
} catch (IllegalArgumentException iae) {
System.err.println("No suitable SchemaFactory for XML Schema validation found!");
} catch (SAXException e) {
throw new ExceptionInInitializerError(e);
}
IF_SCHEMA = ifSchema;
}

/**
* Creates a new test case.
*
* @param testFile the file containing the document and the tests
* @throws IOException if an I/O error occurs while loading the test case
*/
public AbstractIFTestCase(File testFile) throws IOException {
super(testFile);
}

@Override
protected String getIntermediateFileExtension() {
return ".if.xml";
}

@Override
protected Document buildIntermediateDocument(Templates templates) throws Exception {
Transformer transformer = templates.newTransformer();
setErrorListener(transformer);

//Set up XMLRenderer to render to a DOM
DOMResult domResult = new DOMResult();

FOUserAgent userAgent = createUserAgent();

//Create an instance of the target renderer so the XMLRenderer can use its font setup
IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler(
userAgent, getTargetMIME());

//Setup painter
IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(userAgent));
serializer.mimicDocumentHandler(targetHandler);
serializer.setResult(domResult);

userAgent.setDocumentHandlerOverride(serializer);

Fop fop = fopFactory.newFop(userAgent);
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(new DOMSource(testDoc), res);

return (Document) domResult.getNode();
}

@Override
protected void validate(Document doc) throws SAXException, IOException {
if (IF_SCHEMA == null) {
return; //skip validation;
}
Validator validator = IF_SCHEMA.newValidator();
validator.setErrorHandler(new ErrorHandler() {

public void error(SAXParseException exception) throws SAXException {
throw exception;
}

public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}

public void warning(SAXParseException exception) throws SAXException {
//ignore
}

});
validator.validate(new DOMSource(doc));
}

}

+ 9
- 11
test/java/org/apache/fop/intermediate/AbstractIntermediateTestCase.java View File

@@ -44,7 +44,6 @@ import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.events.model.EventSeverity;
import org.apache.fop.layoutengine.TestEnvironment;
import org.apache.fop.util.ConsoleEventListenerForTests;

/**
@@ -53,15 +52,13 @@ import org.apache.fop.util.ConsoleEventListenerForTests;
public abstract class AbstractIntermediateTestCase extends XMLTestCase {

/** the test environment */
protected static TestEnvironment env = new TestEnvironment();
protected static TestAssistant testAssistant = new TestAssistant();

/** the FOP factory */
protected FopFactory fopFactory;

/** the main base directory for tests */
protected File mainDir = new File("test/layoutengine");
/** the directory containing the tests */
protected File testDir = new File(mainDir, "standard-testcases");
protected File testDir = new File("test/layoutengine/standard-testcases");
/** the output directory for any files generated by the tests */
protected File outputDir;

@@ -87,11 +84,11 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase {
protected void setUp() throws Exception {
super.setUp();
setupOutputDirectory();
this.testDoc = env.loadTestCase(testFile);
this.fopFactory = env.getFopFactory(testDoc);
intermediate = buildIntermediateDocument(env.getTestcase2FOStylesheet());
this.testDoc = testAssistant.loadTestCase(testFile);
this.fopFactory = testAssistant.getFopFactory(testDoc);
intermediate = buildIntermediateDocument(testAssistant.getTestcase2FOStylesheet());
if (outputDir != null) {
env.saveDOM(intermediate, new File(outputDir,
testAssistant.saveDOM(intermediate, new File(outputDir,
getName() + ".1" + getIntermediateFileExtension()));
}
}
@@ -148,7 +145,8 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase {
userAgent.getEventBroadcaster().addEventListener(
new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.FATAL));
} catch (MalformedURLException e) {
//ignore, won't happen
// Shouldn't happen
throw new AssertionError();
}
return userAgent;
}
@@ -175,7 +173,7 @@ public abstract class AbstractIntermediateTestCase extends XMLTestCase {
Document doc = parseAndRenderToIntermediateFormat(src);
if (outputDir != null) {
File tgtFile = new File(outputDir, getName() + ".2" + getIntermediateFileExtension());
env.saveDOM(doc, tgtFile);
testAssistant.saveDOM(doc, tgtFile);
}

assertXMLEqual(intermediate, doc);

+ 2
- 2
test/java/org/apache/fop/intermediate/AreaTreeParserTestCase.java View File

@@ -72,7 +72,7 @@ public class AreaTreeParserTestCase extends AbstractIntermediateTestCase {
setErrorListener(transformer);

//Set up XMLRenderer to render to a DOM
TransformerHandler handler = env.getTransformerFactory().newTransformerHandler();
TransformerHandler handler = testAssistant.getTransformerFactory().newTransformerHandler();
DOMResult domResult = new DOMResult();
handler.setResult(domResult);

@@ -113,7 +113,7 @@ public class AreaTreeParserTestCase extends AbstractIntermediateTestCase {
AreaTreeParser parser = new AreaTreeParser();

//Set up XMLRenderer to render to a DOM
TransformerHandler handler = env.getTransformerFactory().newTransformerHandler();
TransformerHandler handler = testAssistant.getTransformerFactory().newTransformerHandler();
DOMResult domResult = new DOMResult();
handler.setResult(domResult);
XMLRenderer renderer = new XMLRenderer();

+ 3
- 1
test/java/org/apache/fop/intermediate/IFCheck.java View File

@@ -21,10 +21,12 @@ package org.apache.fop.intermediate;

import org.w3c.dom.Document;

import org.apache.fop.check.Check;

/**
* Check interface for intermediate format checks.
*/
public interface IFCheck {
public interface IFCheck extends Check {

/**
* Called to perform the check.

+ 49
- 0
test/java/org/apache/fop/intermediate/IFChecksFactory.java View File

@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.intermediate;

import org.w3c.dom.Element;

import org.apache.fop.check.ChecksFactory;
import org.apache.fop.layoutengine.EvalCheck;
import org.apache.fop.layoutengine.TrueCheck;

/**
* A factory class for creating {@link IFCheck} instances.
*/
final class IFChecksFactory extends ChecksFactory<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);
}

});
}
}

+ 10
- 107
test/java/org/apache/fop/intermediate/IFParserTestCase.java View File

@@ -23,59 +23,23 @@ import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.XMLConstants;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;

import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.layoutengine.TestEnvironment;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFParser;
import org.apache.fop.render.intermediate.IFRenderer;
import org.apache.fop.render.intermediate.IFSerializer;

/**
* Tests the intermediate format parser.
*/
public class IFParserTestCase extends AbstractIntermediateTestCase {

private static TestEnvironment env = new TestEnvironment();
private static Schema ifSchema;

private static Schema getIFSchema() throws SAXException {
if (ifSchema == null) {
SchemaFactory sFactory;
try {
sFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
} catch (IllegalArgumentException iae) {
System.out.println("No suitable SchemaFactory for XML Schema validation found!");
return null;
}
File ifSchemaFile = new File(
"src/documentation/intermediate-format-ng/fop-intermediate-format-ng.xsd");
ifSchema = sFactory.newSchema(ifSchemaFile);
}
return ifSchema;
}
public class IFParserTestCase extends AbstractIFTestCase {

/**
* Constructor for the test suite that is used for each test file.
@@ -87,76 +51,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {
}

/** {@inheritDoc} */
protected String getTargetMIME() {
return MimeConstants.MIME_PDF;
}

/** {@inheritDoc} */
protected String getIntermediateFileExtension() {
return ".if.xml";
}

/** {@inheritDoc} */
protected Document buildIntermediateDocument(Templates templates)
throws Exception {
Transformer transformer = templates.newTransformer();
setErrorListener(transformer);

//Set up XMLRenderer to render to a DOM
DOMResult domResult = new DOMResult();

FOUserAgent userAgent = createUserAgent();

//Create an instance of the target renderer so the XMLRenderer can use its font setup
IFDocumentHandler targetHandler = userAgent.getRendererFactory().createDocumentHandler(
userAgent, getTargetMIME());

//Setup painter
IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(userAgent));
serializer.mimicDocumentHandler(targetHandler);
serializer.setResult(domResult);

//Setup renderer
IFRenderer renderer = new IFRenderer();
renderer.setUserAgent(userAgent);

renderer.setDocumentHandler(serializer);
userAgent.setRendererOverride(renderer);

Fop fop = fopFactory.newFop(userAgent);
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(new DOMSource(testDoc), res);

return (Document)domResult.getNode();
}

/** {@inheritDoc} */
protected void validate(Document doc) throws SAXException, IOException {
Schema schema = getIFSchema();
if (schema == null) {
return; //skip validation;
}
Validator validator = schema.newValidator();
validator.setErrorHandler(new ErrorHandler() {

public void error(SAXParseException exception) throws SAXException {
throw exception;
}

public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}

public void warning(SAXParseException exception) throws SAXException {
//ignore
}

});
validator.validate(new DOMSource(doc));
}

/** {@inheritDoc} */
@Override
protected void parseAndRender(Source src, OutputStream out) throws Exception {
IFParser parser = new IFParser();

@@ -170,6 +65,7 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {
}

/** {@inheritDoc} */
@Override
protected Document parseAndRenderToIntermediateFormat(Source src) throws Exception {
IFParser parser = new IFParser();

@@ -185,4 +81,11 @@ public class IFParserTestCase extends AbstractIntermediateTestCase {
return (Document)domResult.getNode();
}

/** {@inheritDoc} */
@Override
public void runTest() throws Exception {
testParserToIntermediateFormat();
testParserToPDF();
}

}

+ 77
- 0
test/java/org/apache/fop/intermediate/IFTestCase.java View File

@@ -0,0 +1,77 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.intermediate;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.transform.Source;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;


/**
* Test case for the IF output.
*/
public class IFTestCase extends AbstractIFTestCase {

private final IFTester ifTester;

/**
* Creates a new test case.
*
* @param test the file containing the test case
* @param ifTester the helper instance that will perform checks
* @throws IOException if an I/O error occurs while loading the test case
*/
public IFTestCase(File test, IFTester ifTester) throws IOException {
super(test);
this.ifTester = ifTester;
this.testDir = test.getParentFile();
}

/** {@inheritDoc} */
@Override
protected void runTest() throws Exception {
Element testRoot = testAssistant.getTestRoot(testFile);
NodeList nodes = testRoot.getElementsByTagName("if-checks");
if (nodes.getLength() == 0) {
throw new RuntimeException("No IF check found");
}
Element ifChecks = (Element) nodes.item(0);

Document doc = buildIntermediateDocument(testAssistant.getTestcase2FOStylesheet());
ifTester.doIFChecks(getName(), ifChecks, doc);
}

@Override
protected void parseAndRender(Source src, OutputStream out) throws Exception {
throw new IllegalStateException("Not applicable to this test");
}

@Override
protected Document parseAndRenderToIntermediateFormat(Source src) throws Exception {
throw new IllegalStateException("Not applicable to this test");
}

}

+ 17
- 136
test/java/org/apache/fop/intermediate/IFTester.java View File

@@ -20,182 +20,63 @@
package org.apache.fop.intermediate;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.events.model.EventSeverity;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.layoutengine.EvalCheck;
import org.apache.fop.layoutengine.TrueCheck;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFRenderer;
import org.apache.fop.render.intermediate.IFSerializer;
import org.apache.fop.util.ConsoleEventListenerForTests;
import org.apache.fop.util.DelegatingContentHandler;

/**
* Does tests on the intermediate format.
*/
public class IFTester {

private static final Map IF_CHECK_CLASSES = new java.util.HashMap();

static {
IF_CHECK_CLASSES.put("true", TrueCheck.class);
IF_CHECK_CLASSES.put("eval", EvalCheck.class);
}

private FopFactory fopFactory = FopFactory.newInstance();
private final IFChecksFactory ifChecksFactory = new IFChecksFactory();

private SAXTransformerFactory tfactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
private final TransformerFactory tfactory;

private File backupDir;

/**
* Main constructor
* Main constructor.
*
* @param transformerFactory the factory used to serialize the intermediate format files
* @param backupDir an optional directory in which to write the serialized
* intermediate format file (may be null)
* IF files (may be null)
*/
public IFTester(File backupDir) {
public IFTester(TransformerFactory transformerFactory, File backupDir) {
this.tfactory = transformerFactory;
this.backupDir = backupDir;
}

/**
* Factory method to create IF checks from DOM elements.
* @param el DOM element to create the check from
* @return The newly create check
*/
protected IFCheck createIFCheck(Element el) {
String name = el.getTagName();
Class clazz = (Class)IF_CHECK_CLASSES.get(name);
if (clazz != null) {
try {
Constructor c = clazz.getDeclaredConstructor(new Class[] {Node.class});
IFCheck instance = (IFCheck)c.newInstance(new Object[] {el});
return instance;
} catch (Exception e) {
throw new RuntimeException("Error while instantiating check '"
+ name + "': " + e.getMessage());
}
} else {
throw new IllegalArgumentException("No check class found: " + name);
}
}

private Document createIF(File testFile, Document areaTreeXML) throws TransformerException {
try {
FOUserAgent ua = fopFactory.newFOUserAgent();
ua.setBaseURL(testFile.getParentFile().toURI().toURL().toExternalForm());
ua.getEventBroadcaster().addEventListener(
new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN));

IFRenderer ifRenderer = new IFRenderer();
ifRenderer.setUserAgent(ua);

IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(ua));
DOMResult result = new DOMResult();
serializer.setResult(result);
ifRenderer.setDocumentHandler(serializer);

ua.setRendererOverride(ifRenderer);
FontInfo fontInfo = new FontInfo();
//Construct the AreaTreeModel that will received the individual pages
final AreaTreeModel treeModel = new RenderPagesModel(ua,
null, fontInfo, null);

//Iterate over all intermediate files
AreaTreeParser parser = new AreaTreeParser();
ContentHandler handler = parser.getContentHandler(treeModel, ua);

DelegatingContentHandler proxy = new DelegatingContentHandler() {

public void endDocument() throws SAXException {
super.endDocument();
//Signal the end of the processing.
//The renderer can finalize the target document.
treeModel.endDocument();
}

};
proxy.setDelegateContentHandler(handler);

Transformer transformer = tfactory.newTransformer();
transformer.transform(new DOMSource(areaTreeXML), new SAXResult(proxy));

return (Document)result.getNode();
} catch (Exception e) {
throw new TransformerException(
"Error while generating intermediate format file: " + e.getMessage(), e);
}
}

/**
* Runs the intermediate format checks.
* @param testFile the original test file
* @param testName the name of the test case
* @param checksRoot the root element containing the IF checks
* @param areaTreeXML the area tree XML
* @param ifDocument the IF XML
* @throws TransformerException if an error occurs while transforming the content
*/
public void doIFChecks(File testFile, Element checksRoot, Document areaTreeXML)
throws TransformerException {
Document ifDocument = createIF(testFile, areaTreeXML);
public void doIFChecks(String testName, Element checksRoot, Document ifDocument)
throws TransformerException {
if (this.backupDir != null) {
Transformer transformer = tfactory.newTransformer();
Source src = new DOMSource(ifDocument);
File targetFile = new File(this.backupDir, testFile.getName() + ".if.xml");
File targetFile = new File(this.backupDir, testName + ".if.xml");
Result res = new StreamResult(targetFile);
transformer.transform(src, res);
}

//First create check before actually running them
List checks = new java.util.ArrayList();
NodeList nodes = checksRoot.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
checks.add(createIFCheck((Element)node));
}
}

List<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);
}
}

+ 26
- 30
test/java/org/apache/fop/intermediate/IntermediateFormatTestSuite.java View File

@@ -20,52 +20,48 @@
package org.apache.fop.intermediate;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import javax.xml.transform.TransformerFactory;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.apache.fop.layoutengine.LayoutEngineTestSuite;

/**
* JUnit test suite for the intermediate format
* A test suite for testing the Intermediate Format output.
*/
public class IntermediateFormatTestSuite {
public final class IntermediateFormatTestSuite {

private IntermediateFormatTestSuite() {
// This is a utility class
}

/**
* @return the test suite with all the tests (one for each XML file)
* @throws IOException in case of an I/O problem
* Creates a suite of Intermediate Format tests.
*
* @return the test suite
* @throws IOException if an I/O error occurs while loading one of the tests
*/
public static Test suite() throws IOException {
TestSuite suite = new TestSuite();

Collection files = LayoutEngineTestSuite.getTestFiles();
File backupDir = new File("build/test-results/intermediate");
backupDir.mkdirs();

Iterator i = files.iterator();
while (i.hasNext()) {
File f = (File)i.next();
addIFTestCase(suite, f);
}
IFTester ifTester = new IFTester(TransformerFactory.newInstance(), backupDir);

return suite;
}
TestSuite suite = new TestSuite();
File testDir = new File("test/intermediate");
String[] tests = testDir.list(new FilenameFilter() {

private static void addIFTestCase(TestSuite suite,
final File f) throws IOException {
suite.addTest(new IFParserTestCase(f) {
public void runTest() throws Exception {
try {
testParserToIntermediateFormat();
testParserToPDF();
} catch (Exception e) {
org.apache.commons.logging.LogFactory.getLog(
this.getClass()).error("Error on " + f.getName());
throw e;
}
public boolean accept(File dir, String name) {
return name.endsWith(".xml");
}
});
for (String test : tests) {
File testFile = new File(testDir, test);
suite.addTest(new IFTestCase(testFile, ifTester));
}
return suite;
}

}

+ 64
- 0
test/java/org/apache/fop/intermediate/LayoutIFTestSuite.java View File

@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.intermediate;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;

import junit.framework.Test;
import junit.framework.TestSuite;

import org.apache.fop.layoutengine.LayoutEngineTestSuite;

/**
* JUnit test suite for the intermediate format
*/
public final class LayoutIFTestSuite {

private LayoutIFTestSuite() {
// This is a utility class
}

/**
* @return the test suite with all the tests (one for each XML file)
* @throws IOException in case of an I/O problem
*/
public static Test suite() throws IOException {
TestSuite suite = new TestSuite();

Collection files = LayoutEngineTestSuite.getTestFiles();

Iterator i = files.iterator();
while (i.hasNext()) {
File f = (File)i.next();
addIFTestCase(suite, f);
}

return suite;
}

private static void addIFTestCase(TestSuite suite,
final File f) throws IOException {
suite.addTest(new IFParserTestCase(f));
}

}

test/java/org/apache/fop/layoutengine/TestEnvironment.java → test/java/org/apache/fop/intermediate/TestAssistant.java View File

@@ -17,7 +17,7 @@

/* $Id$ */

package org.apache.fop.layoutengine;
package org.apache.fop.intermediate;

import java.io.File;
import java.io.IOException;
@@ -30,12 +30,14 @@ 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;
@@ -43,9 +45,9 @@ import org.apache.xpath.objects.XObject;
import org.apache.fop.apps.FopFactory;

/**
* Test environment and helper code for running FOP tests.
* Helper class for running FOP tests.
*/
public class TestEnvironment {
public class TestAssistant {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();
@@ -62,7 +64,7 @@ public class TestEnvironment {
/**
* Main constructor.
*/
public TestEnvironment() {
public TestAssistant() {
fopFactory.getFontManager().setBase14KerningEnabled(false);
fopFactoryWithBase14Kerning.getFontManager().setBase14KerningEnabled(true);
domBuilderFactory = DocumentBuilderFactory.newInstance();
@@ -89,7 +91,7 @@ public class TestEnvironment {
* @return the stylesheet
* @throws TransformerConfigurationException if an error occurs loading the stylesheet
*/
public Templates getTestcase2ChecksStylesheet() throws TransformerConfigurationException {
private Templates getTestcase2ChecksStylesheet() throws TransformerConfigurationException {
if (testcase2checks == null) {
//Load and cache stylesheet
Source src = new StreamSource(new File("test/layoutengine/testcase2checks.xsl"));
@@ -98,6 +100,21 @@ public class TestEnvironment {
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;

+ 0
- 10
test/java/org/apache/fop/layoutengine/EvalCheck.java View File

@@ -41,16 +41,6 @@ public class EvalCheck implements LayoutEngineCheck, IFCheck {
private double tolerance;
private PrefixResolver prefixResolver;

/**
* Creates a new instance
* @param expected expected value
* @param xpath XPath statement that needs to be evaluated
*/
public EvalCheck(String expected, String xpath) {
this.expected = expected;
this.xpath = xpath;
}

/**
* Creates a new instance from a DOM node.
* @param node DOM node that defines this check

+ 3
- 1
test/java/org/apache/fop/layoutengine/LayoutEngineCheck.java View File

@@ -19,10 +19,12 @@

package org.apache.fop.layoutengine;

import org.apache.fop.check.Check;

/**
* Defines the interface for check operations.
*/
public interface LayoutEngineCheck {
public interface LayoutEngineCheck extends Check {

/**
* Called to perform the check.

+ 62
- 0
test/java/org/apache/fop/layoutengine/LayoutEngineChecksFactory.java View File

@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.layoutengine;

import org.w3c.dom.Element;

import org.apache.fop.check.ChecksFactory;

/**
* A factory class for creating {@link LayoutEngineCheck} instances.
*/
final class LayoutEngineChecksFactory extends ChecksFactory<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);
}

});
}

}

+ 20
- 28
test/java/org/apache/fop/layoutengine/LayoutEngineTestSuite.java View File

@@ -56,12 +56,16 @@ import org.apache.fop.DebugHelper;
/**
* JUnit test suit for running layout engine test under JUnit control.
*/
public class LayoutEngineTestSuite {
public final class LayoutEngineTestSuite {

static {
DebugHelper.registerStandardElementListObservers();
}

private LayoutEngineTestSuite() {
// This is a utility class
}

public static String[] readDisabledTestcases(File f) throws IOException {
List lines = new java.util.ArrayList();
Source stylesheet = new StreamSource(
@@ -178,45 +182,33 @@ public class LayoutEngineTestSuite {
Iterator i = files.iterator();
while (i.hasNext()) {
File f = (File)i.next();
addTestCase(suite, tester, f);
suite.addTest(new LayoutEngineTestCase(f, tester));
}

return suite;
}

private static void addTestCase(TestSuite suite,
final LayoutEngineTester tester, final File f) {
suite.addTest(new LayoutEngineTestCase(f.getName()) {
public void runTest() throws Exception {
try {
prepare(tester, f);
testMain();
} catch (Exception e) {
org.apache.commons.logging.LogFactory.getLog(
this.getClass()).error("Error on " + f.getName());
throw e;
}
}
});
}

private static class LayoutEngineTestCase extends TestCase {

private LayoutEngineTester tester;
private File testFile;
private final File testFile;

public LayoutEngineTestCase(String name) {
super(name);
}
private final LayoutEngineTester tester;

public void prepare(LayoutEngineTester tester, File testFile) {
//super(testFile.getName());
this.tester = tester;
LayoutEngineTestCase(File testFile, LayoutEngineTester tester) {
super(testFile.getName());
this.testFile = testFile;
this.tester = tester;
}

public void testMain() throws Exception {
tester.runTest(testFile);
@Override
protected void runTest() throws Throwable {
try {
tester.runTest(testFile);
} catch (Exception e) {
org.apache.commons.logging.LogFactory.getLog(
this.getClass()).error("Error on " + getName());
throw e;
}
}
}
}

+ 80
- 76
test/java/org/apache/fop/layoutengine/LayoutEngineTester.java View File

@@ -21,37 +21,42 @@ package org.apache.fop.layoutengine;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.FormattingResults;
import org.apache.fop.area.AreaTreeModel;
import org.apache.fop.area.AreaTreeParser;
import org.apache.fop.area.RenderPagesModel;
import org.apache.fop.events.model.EventSeverity;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.intermediate.IFTester;
import org.apache.fop.intermediate.TestAssistant;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFRenderer;
import org.apache.fop.render.intermediate.IFSerializer;
import org.apache.fop.render.xml.XMLRenderer;
import org.apache.fop.util.ConsoleEventListenerForTests;
import org.apache.fop.util.DelegatingContentHandler;

/**
* Class for testing the FOP's layout engine using testcases specified in XML
@@ -59,19 +64,13 @@ import org.apache.fop.util.ConsoleEventListenerForTests;
*/
public class LayoutEngineTester {

private static final Map AT_CHECK_CLASSES = new java.util.HashMap();

private TestEnvironment env = new TestEnvironment();
private TestAssistant testAssistant = new TestAssistant();

private LayoutEngineChecksFactory layoutEngineChecksFactory = new LayoutEngineChecksFactory();
private File areaTreeBackupDir;
private IFTester ifTester;

static {
AT_CHECK_CLASSES.put("true", TrueCheck.class);
AT_CHECK_CLASSES.put("eval", EvalCheck.class);
AT_CHECK_CLASSES.put("element-list", ElementListCheck.class);
AT_CHECK_CLASSES.put("result", ResultCheck.class);
}
private TransformerFactory tfactory = TransformerFactory.newInstance();

/**
* Constructs a new instance.
@@ -80,7 +79,7 @@ public class LayoutEngineTester {
*/
public LayoutEngineTester(File areaTreeBackupDir) {
this.areaTreeBackupDir = areaTreeBackupDir;
this.ifTester = new IFTester(areaTreeBackupDir);
this.ifTester = new IFTester(tfactory, areaTreeBackupDir);
}

/**
@@ -100,18 +99,18 @@ public class LayoutEngineTester {
ElementListObserver.addObserver(elCollector);

Fop fop;
FopFactory effFactory;
try {
Document testDoc = env.loadTestCase(testFile);
FopFactory effFactory = env.getFopFactory(testDoc);
Document testDoc = testAssistant.loadTestCase(testFile);
effFactory = testAssistant.getFopFactory(testDoc);

//Setup Transformer to convert the testcase XML to XSL-FO
Transformer transformer = env.getTestcase2FOStylesheet().newTransformer();
Transformer transformer = testAssistant.getTestcase2FOStylesheet().newTransformer();
Source src = new DOMSource(testDoc);

//Setup Transformer to convert the area tree to a DOM
TransformerHandler athandler;
athandler = env.getTransformerFactory().newTransformerHandler();
athandler = testAssistant.getTransformerFactory().newTransformerHandler();
athandler.setResult(domres);

//Setup FOP for area tree rendering
@@ -134,91 +133,96 @@ public class LayoutEngineTester {

Document doc = (Document)domres.getNode();
if (this.areaTreeBackupDir != null) {
env.saveDOM(doc,
testAssistant.saveDOM(doc,
new File(this.areaTreeBackupDir, testFile.getName() + ".at.xml"));
}
FormattingResults results = fop.getResults();
LayoutResult result = new LayoutResult(doc, elCollector, results);
checkAll(testFile, result);
checkAll(effFactory, testFile, result);
}

/**
* Factory method to create AT checks from DOM elements.
* @param el DOM element to create the check from
* @return The newly create check
*/
protected LayoutEngineCheck createATCheck(Element el) {
String name = el.getTagName();
Class clazz = (Class)AT_CHECK_CLASSES.get(name);
if (clazz != null) {
try {
Constructor c = clazz.getDeclaredConstructor(new Class[] {Node.class});
LayoutEngineCheck instance = (LayoutEngineCheck)c.newInstance(new Object[] {el});
return instance;
} catch (Exception e) {
throw new RuntimeException("Error while instantiating check '"
+ name + "': " + e.getMessage());
}
} else {
throw new IllegalArgumentException("No check class found: " + name);
}
}


/**
* Perform all checks on the area tree and, optionally, on the intermediate format.
* @param testFile Test case XML file
* @param result The layout results
* @throws TransformerException if a problem occurs in XSLT/JAXP
*/
protected void checkAll(File testFile, LayoutResult result) throws TransformerException {
Transformer transformer = env.getTestcase2ChecksStylesheet().newTransformer();
Source src = new StreamSource(testFile);
DOMResult res = new DOMResult();
transformer.transform(src, res);

Document doc = (Document)res.getNode();
Element root = doc.getDocumentElement();
protected void checkAll(FopFactory fopFactory, File testFile, LayoutResult result)
throws TransformerException {
Element testRoot = testAssistant.getTestRoot(testFile);

NodeList nodes;
//AT tests only when checks are available
nodes = root.getElementsByTagName("at-checks");
nodes = testRoot.getElementsByTagName("at-checks");
if (nodes.getLength() > 0) {
Element atChecks = (Element)nodes.item(0);
doATChecks(atChecks, result);
}

//IF tests only when checks are available
nodes = root.getElementsByTagName("if-checks");
nodes = testRoot.getElementsByTagName("if-checks");
if (nodes.getLength() > 0) {
Element ifChecks = (Element)nodes.item(0);
ifTester.doIFChecks(testFile, ifChecks, result.getAreaTree());
Document ifDocument = createIF(fopFactory, testFile, result.getAreaTree());
ifTester.doIFChecks(testFile.getName(), ifChecks, ifDocument);
}
}

private void doATChecks(Element checksRoot, LayoutResult result) {
//First create check before actually running them
List checks = new java.util.ArrayList();
NodeList nodes = checksRoot.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
checks.add(createATCheck((Element)node));
}
}
private Document createIF(FopFactory fopFactory, File testFile, Document areaTreeXML)
throws TransformerException {
try {
FOUserAgent ua = fopFactory.newFOUserAgent();
ua.setBaseURL(testFile.getParentFile().toURI().toURL().toExternalForm());
ua.getEventBroadcaster().addEventListener(
new ConsoleEventListenerForTests(testFile.getName(), EventSeverity.WARN));

if (checks.size() == 0) {
throw new RuntimeException("No checks are available!");
}
IFRenderer ifRenderer = new IFRenderer();
ifRenderer.setUserAgent(ua);

IFSerializer serializer = new IFSerializer();
serializer.setContext(new IFContext(ua));
DOMResult result = new DOMResult();
serializer.setResult(result);
ifRenderer.setDocumentHandler(serializer);

ua.setRendererOverride(ifRenderer);
FontInfo fontInfo = new FontInfo();
//Construct the AreaTreeModel that will received the individual pages
final AreaTreeModel treeModel = new RenderPagesModel(ua,
null, fontInfo, null);

//Iterate over all intermediate files
AreaTreeParser parser = new AreaTreeParser();
ContentHandler handler = parser.getContentHandler(treeModel, ua);

DelegatingContentHandler proxy = new DelegatingContentHandler() {

//Run the actual tests now that we know that the checks themselves are ok
doATChecks(checks, result);
public void endDocument() throws SAXException {
super.endDocument();
//Signal the end of the processing.
//The renderer can finalize the target document.
treeModel.endDocument();
}

};
proxy.setDelegateContentHandler(handler);

Transformer transformer = tfactory.newTransformer();
transformer.transform(new DOMSource(areaTreeXML), new SAXResult(proxy));

return (Document)result.getNode();
} catch (Exception e) {
throw new TransformerException(
"Error while generating intermediate format file: " + e.getMessage(), e);
}
}

private void doATChecks(List checks, LayoutResult result) {
Iterator i = checks.iterator();
while (i.hasNext()) {
LayoutEngineCheck check = (LayoutEngineCheck)i.next();
private void doATChecks(Element checksRoot, LayoutResult result) {
List<LayoutEngineCheck> checks = layoutEngineChecksFactory.createCheckList(checksRoot);
if (checks.size() == 0) {
throw new RuntimeException("No available area tree check");
}
for (LayoutEngineCheck check : checks) {
check.check(result);
}
}

+ 2
- 11
test/java/org/apache/fop/layoutengine/ResultCheck.java View File

@@ -19,9 +19,10 @@

package org.apache.fop.layoutengine;

import org.apache.fop.apps.FormattingResults;
import org.w3c.dom.Node;

import org.apache.fop.apps.FormattingResults;

/**
* Simple check that requires a result property to evaluate to the expected value
*/
@@ -30,16 +31,6 @@ public class ResultCheck implements LayoutEngineCheck {
private String expected;
private String property;

/**
* Creates a new instance
* @param expected expected value
* @param property property of which the value needs to be evaluated
*/
public ResultCheck(String expected, String property) {
this.expected = expected;
this.property = property;
}

/**
* Creates a new instance from a DOM node.
* @param node DOM node that defines this check

+ 0
- 8
test/java/org/apache/fop/layoutengine/TrueCheck.java View File

@@ -41,14 +41,6 @@ public class TrueCheck implements LayoutEngineCheck, IFCheck {
private String failureMessage;
private PrefixResolver prefixResolver;

/**
* Creates a new instance
* @param xpath XPath statement that needs to be evaluated
*/
public TrueCheck(String xpath) {
this.xpath = xpath;
}

/**
* Creates a new instance from a DOM node.
* @param node DOM node that defines this check

Loading…
Cancel
Save