Browse Source

Associate structure tree elements directly to render content

* Defer the binding of PCData to struct elems using a placeholder mechanism.
* Translate text nodes to marked-content sequences in IF structure tree.
* Replace ptr with structure tree element.
* Re-order table footers so they appear at the end of the structure tree.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ImproveAccessibility@1236718 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_1rc1old
Peter Hancock 12 years ago
parent
commit
160d78ce1c
88 changed files with 1968 additions and 845 deletions
  1. 1
    0
      build.xml
  2. 17
    6
      src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java
  3. 27
    8
      src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java
  4. 8
    11
      src/java/org/apache/fop/accessibility/StructureTreeElement.java
  5. 27
    4
      src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java
  6. 29
    361
      src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java
  7. 508
    0
      src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java
  8. 408
    0
      src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java
  9. 0
    11
      src/java/org/apache/fop/area/AreaTreeParser.java
  10. 3
    3
      src/java/org/apache/fop/area/Trait.java
  11. 2
    2
      src/java/org/apache/fop/fo/DelegatingFOEventHandler.java
  12. 6
    4
      src/java/org/apache/fop/fo/FOEventHandler.java
  13. 2
    1
      src/java/org/apache/fop/fo/FONode.java
  14. 17
    16
      src/java/org/apache/fop/fo/FOText.java
  15. 1
    1
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  16. 8
    1
      src/java/org/apache/fop/fo/extensions/InternalElementMapping.java
  17. 8
    7
      src/java/org/apache/fop/fo/flow/AbstractGraphics.java
  18. 8
    7
      src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java
  19. 8
    7
      src/java/org/apache/fop/fo/flow/BasicLink.java
  20. 1
    13
      src/java/org/apache/fop/fo/flow/Block.java
  21. 8
    7
      src/java/org/apache/fop/fo/flow/Character.java
  22. 1
    13
      src/java/org/apache/fop/fo/flow/Inline.java
  23. 8
    7
      src/java/org/apache/fop/fo/flow/PageNumber.java
  24. 1
    13
      src/java/org/apache/fop/fo/flow/table/TableFObj.java
  25. 38
    0
      src/java/org/apache/fop/fo/properties/StructureTreeElementHolder.java
  26. 0
    1
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  27. 8
    6
      src/java/org/apache/fop/layoutmgr/TraitSetter.java
  28. 1
    1
      src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java
  29. 1
    1
      src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java
  30. 1
    1
      src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
  31. 1
    1
      src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
  32. 4
    4
      src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java
  33. 1
    17
      src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
  34. 73
    29
      src/java/org/apache/fop/pdf/PDFStructElem.java
  35. 18
    15
      src/java/org/apache/fop/render/intermediate/IFContext.java
  36. 38
    18
      src/java/org/apache/fop/render/intermediate/IFParser.java
  37. 12
    9
      src/java/org/apache/fop/render/intermediate/IFRenderer.java
  38. 21
    8
      src/java/org/apache/fop/render/intermediate/IFSerializer.java
  39. 81
    37
      src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java
  40. 8
    6
      src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java
  41. 17
    7
      src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java
  42. 4
    4
      src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
  43. 28
    56
      src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
  44. 11
    10
      src/java/org/apache/fop/render/pdf/PDFPainter.java
  45. 51
    20
      src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java
  46. 5
    7
      src/java/org/apache/fop/render/rtf/RTFHandler.java
  47. 2
    2
      test/accessibility/background-image_jpg_repeat.fo
  48. 2
    2
      test/accessibility/background-image_jpg_single.fo
  49. 2
    2
      test/accessibility/background-image_png_repeat.fo
  50. 2
    2
      test/accessibility/background-image_png_single.fo
  51. 2
    2
      test/accessibility/background-image_svg_repeat.fo
  52. 2
    2
      test/accessibility/background-image_svg_single.fo
  53. 3
    3
      test/accessibility/complete.fo
  54. 2
    2
      test/accessibility/image_jpg.fo
  55. 2
    2
      test/accessibility/image_png.fo
  56. 2
    2
      test/accessibility/image_svg.fo
  57. 2
    2
      test/accessibility/image_wmf.fo
  58. 2
    2
      test/accessibility/leader.fo
  59. 2
    2
      test/accessibility/links.fo
  60. BIN
      test/accessibility/pdf/background-image_jpg_repeat.pdf
  61. BIN
      test/accessibility/pdf/background-image_jpg_single.pdf
  62. BIN
      test/accessibility/pdf/background-image_png_repeat.pdf
  63. BIN
      test/accessibility/pdf/background-image_png_single.pdf
  64. BIN
      test/accessibility/pdf/background-image_svg_repeat.pdf
  65. BIN
      test/accessibility/pdf/background-image_svg_single.pdf
  66. BIN
      test/accessibility/pdf/complete.pdf
  67. BIN
      test/accessibility/pdf/image_jpg.pdf
  68. BIN
      test/accessibility/pdf/image_png.pdf
  69. BIN
      test/accessibility/pdf/image_svg.pdf
  70. BIN
      test/accessibility/pdf/image_wmf.pdf
  71. BIN
      test/accessibility/pdf/leader.pdf
  72. BIN
      test/accessibility/pdf/links.pdf
  73. BIN
      test/accessibility/pdf/role.pdf
  74. BIN
      test/accessibility/pdf/role_non-standard.pdf
  75. BIN
      test/accessibility/pdf/text_1.pdf
  76. BIN
      test/accessibility/pdf/text_2.pdf
  77. BIN
      test/accessibility/pdf/text_font-embedding.pdf
  78. 2
    2
      test/accessibility/role.fo
  79. 2
    2
      test/accessibility/role_non-standard.fo
  80. 2
    2
      test/accessibility/text_1.fo
  81. 2
    2
      test/accessibility/text_2.fo
  82. 2
    2
      test/accessibility/text_font-embedding.fo
  83. 54
    0
      test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java
  84. 65
    44
      test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java
  85. 21
    2
      test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl
  86. 195
    0
      test/java/org/apache/fop/accessibility/fo/table-footers.fo
  87. 66
    0
      test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl
  88. 1
    1
      test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java

+ 1
- 0
build.xml View File

@@ -581,6 +581,7 @@ list of possible build targets.
<!-- General classes -->
<patternset>
<include name="org/apache/fop/Version.class"/>
<include name="org/apache/fop/accessibility/StructureTreeElement.class"/>
<include name="org/apache/fop/apps/Fop.class"/>
<include name="org/apache/fop/apps/FOPException.class"/>
<include name="org/apache/fop/fo/Constants.class"/>

+ 17
- 6
src/java/org/apache/fop/accessibility/DummyStructureTreeEventHandler.java View File

@@ -33,20 +33,31 @@ public final class DummyStructureTreeEventHandler implements StructureTreeEventH

private DummyStructureTreeEventHandler() { }

/** {@inheritDoc} */
public void startPageSequence(Locale locale) {
}

/** {@inheritDoc} */
public void startNode(String name, Attributes attributes) {
public void endPageSequence() {
}

public StructureTreeElement startNode(String name, Attributes attributes) {
return null;
}

/** {@inheritDoc} */
public void endNode(String name) {
}

/** {@inheritDoc} */
public void endPageSequence() {
public StructureTreeElement startImageNode(String name, Attributes attributes) {
return null;
}

public void endImageNode(String name) {
}

public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
return null;
}

public void endReferencedNode(String name) {
}

}

+ 27
- 8
src/java/org/apache/fop/accessibility/StructureTree2SAXEventAdapter.java View File

@@ -50,7 +50,6 @@ public final class StructureTree2SAXEventAdapter implements StructureTreeEventHa
return new StructureTree2SAXEventAdapter(contentHandler);
}

/** {@inheritDoc} */
public void startPageSequence(Locale locale) {
try {

@@ -66,7 +65,6 @@ public final class StructureTree2SAXEventAdapter implements StructureTreeEventHa
}
}

/** {@inheritDoc} */
public void endPageSequence() {
try {
contentHandler.endElement(IFConstants.NAMESPACE, IFConstants.EL_STRUCTURE_TREE,
@@ -81,18 +79,23 @@ public final class StructureTree2SAXEventAdapter implements StructureTreeEventHa
}
}

/** {@inheritDoc} */
public void startNode(String name, Attributes attributes) {
public StructureTreeElement startNode(String name, Attributes attributes) {
try {
contentHandler.startElement(FOElementMapping.URI, name,
FOElementMapping.STANDARD_PREFIX + ":" + name,
attributes);
if (name.equals("#PCDATA")) {
name = "marked-content";
contentHandler.startElement(IFConstants.NAMESPACE, name,
name, attributes);
} else {
contentHandler.startElement(FOElementMapping.URI, name,
FOElementMapping.STANDARD_PREFIX + ":" + name,
attributes);
}
return null;
} catch (SAXException e) {
throw new RuntimeException(e);
}
}

/** {@inheritDoc} */
public void endNode(String name) {
try {
contentHandler.endElement(FOElementMapping.URI, name,
@@ -101,4 +104,20 @@ public final class StructureTree2SAXEventAdapter implements StructureTreeEventHa
throw new RuntimeException(e);
}
}

public StructureTreeElement startImageNode(String name, Attributes attributes) {
return startNode(name, attributes);
}

public void endImageNode(String name) {
endNode(name);
}

public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
return startNode(name, attributes);
}

public void endReferencedNode(String name) {
endNode(name);
}
}

src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java → src/java/org/apache/fop/accessibility/StructureTreeElement.java View File

@@ -17,18 +17,15 @@

/* $Id$ */

package org.apache.fop.fo.properties;

/**
* Defines property access methods for internal structure pointer extension properties.
*
*/
public interface StructurePointerPropertySet {

/**
* Returns the value of the "foi:ptr" property, the internal structure pointer used
* for tagged PDF and other formats that support a structure tree in addition to paged content.
* @return the "foi:ptr" property
*/
String getPtr();
package org.apache.fop.accessibility;

/**
* An object that represents the structure of the document in the output format.
* In PDF, an implementation of this interface will typically result into the
* creation of a structure element dictionary (a dictionary of type StructElem).
*/
public interface StructureTreeElement {
}

+ 27
- 4
src/java/org/apache/fop/accessibility/StructureTreeEventHandler.java View File

@@ -32,23 +32,46 @@ public interface StructureTreeEventHandler {

/**
* Starts a page sequence structure tree node.
*
* @param locale The locale of the page sequence
*/
void startPageSequence(Locale locale);

/**
* Starts a structure tree node.
* @param name The name of the structure tree node
* @param attributes Map of node properties
*
* @param name the name of the structure tree node
* @param attributes the node properties
* @return the corresponding structure tree element
*/
void startNode(String name, Attributes attributes);
StructureTreeElement startNode(String name, Attributes attributes);

/**
* Ends a structure tree node.
* @param name The name of the structure tree node
*
* @param name the name of the structure tree node
*/
void endNode(String name);

/**
* Starts an image node.
*
* @param name the name of the structure tree node
* @param attributes the node properties
* @return the corresponding structure tree element
*/
StructureTreeElement startImageNode(String name, Attributes attributes);

/**
* Starts a node that can be referenced by other nodes. This is usually a
* node that can have Marked Content References as children.
*
* @param name the name of the structure tree node
* @param attributes the node properties
* @return the corresponding structure tree element
*/
StructureTreeElement startReferencedNode(String name, Attributes attributes);

/**
* Ends a page sequence structure tree node.
*/

src/java/org/apache/fop/accessibility/FO2StructureTreeConverter.java → src/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverter.java View File

@@ -17,21 +17,17 @@

/* $Id$ */

package org.apache.fop.accessibility;
package org.apache.fop.accessibility.fo;

import java.util.Locale;
import java.util.Stack;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fo.DelegatingFOEventHandler;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.extensions.ExternalDocument;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fo.flow.AbstractGraphics;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.BlockContainer;
@@ -61,8 +57,6 @@ import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
import org.apache.fop.util.XMLUtil;

/**
* Allows to create the structure tree of an FO document, by converting FO
@@ -70,354 +64,18 @@ import org.apache.fop.util.XMLUtil;
*/
public class FO2StructureTreeConverter extends DelegatingFOEventHandler {

private int idCounter;

/** Delegates to either {@link #foToStructureTreeEventAdapter} or {@link #eventSwallower}. */
/** The top of the {@link converters} stack. */
private FOEventHandler converter;

private final FOEventHandler foToStructureTreeEventAdapter;

/** The descendants of some elements like fo:leader must be ignored. */
private final FOEventHandler eventSwallower;

private final StructureTreeEventHandler structureTreeEventHandler;

private final class FOToStructureTreeEventAdapter extends FOEventHandler {

public FOToStructureTreeEventAdapter(FOUserAgent foUserAgent) {
super(foUserAgent);
}

@Override
public void startDocument() throws SAXException {
}

@Override
public void endDocument() throws SAXException {
}

@Override
public void startPageSequence(PageSequence pageSeq) {
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
locale = new Locale(pageSeq.getLanguage(), pageSeq.getCountry());
} else {
locale = new Locale(pageSeq.getLanguage());
}
}
structureTreeEventHandler.startPageSequence(locale);
}

@Override
public void endPageSequence(PageSequence pageSeq) {
structureTreeEventHandler.endPageSequence();
}

@Override
public void startPageNumber(PageNumber pagenum) {
startElementWithID(pagenum);
}

@Override
public void endPageNumber(PageNumber pagenum) {
endElement(pagenum);
}

@Override
public void startPageNumberCitation(PageNumberCitation pageCite) {
startElementWithID(pageCite);
}

@Override
public void endPageNumberCitation(PageNumberCitation pageCite) {
endElement(pageCite);
}

@Override
public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
startElementWithID(pageLast);
}

@Override
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
endElement(pageLast);
}

@Override
public void startFlow(Flow fl) {
startElement(fl);
}

@Override
public void endFlow(Flow fl) {
endElement(fl);
}

@Override
public void startBlock(Block bl) {
startElementWithID(bl);
}

@Override
public void endBlock(Block bl) {
endElement(bl);
}
private final Stack<FOEventHandler> converters = new Stack<FOEventHandler>();

@Override
public void startBlockContainer(BlockContainer blc) {
startElement(blc);
}
private final Stack<FOEventRecorder> tableFooterRecorders = new Stack<FOEventRecorder>();

@Override
public void endBlockContainer(BlockContainer blc) {
endElement(blc);
}
private final FOEventHandler structureTreeEventTrigger;

@Override
public void startInline(Inline inl) {
startElementWithID(inl);
}

@Override
public void endInline(Inline inl) {
endElement(inl);
}

@Override
public void startTable(Table tbl) {
startElementWithID(tbl);
}

@Override
public void endTable(Table tbl) {
endElement(tbl);
}

@Override
public void startHeader(TableHeader header) {
startElementWithID(header);
}

@Override
public void endHeader(TableHeader header) {
endElement(header);
}

@Override
public void startFooter(TableFooter footer) {
startElementWithID(footer);
}

@Override
public void endFooter(TableFooter footer) {
endElement(footer);
}

@Override
public void startBody(TableBody body) {
startElementWithID(body);
}

@Override
public void endBody(TableBody body) {
endElement(body);
}

@Override
public void startRow(TableRow tr) {
startElementWithID(tr);
}

@Override
public void endRow(TableRow tr) {
endElement(tr);
}

@Override
public void startCell(TableCell tc) {
AttributesImpl attributes = new AttributesImpl();
int colSpan = tc.getNumberColumnsSpanned();
if (colSpan > 1) {
addNoNamespaceAttribute(attributes, "number-columns-spanned",
Integer.toString(colSpan));
}
startElementWithID(tc, attributes);
}

@Override
public void endCell(TableCell tc) {
endElement(tc);
}

@Override
public void startList(ListBlock lb) {
startElement(lb);
}

@Override
public void endList(ListBlock lb) {
endElement(lb);
}

@Override
public void startListItem(ListItem li) {
startElement(li);
}

@Override
public void endListItem(ListItem li) {
endElement(li);
}

@Override
public void startListLabel(ListItemLabel listItemLabel) {
startElement(listItemLabel);
}

@Override
public void endListLabel(ListItemLabel listItemLabel) {
endElement(listItemLabel);
}

@Override
public void startListBody(ListItemBody listItemBody) {
startElement(listItemBody);
}

@Override
public void endListBody(ListItemBody listItemBody) {
endElement(listItemBody);
}

@Override
public void startStatic(StaticContent staticContent) {
startElement(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
endElement(statisContent);
}

@Override
public void startLink(BasicLink basicLink) {
startElementWithID(basicLink);
}

@Override
public void endLink(BasicLink basicLink) {
endElement(basicLink);
}

@Override
public void image(ExternalGraphic eg) {
startElementWithIDAndAltText(eg);
endElement(eg);
}

@Override
public void startInstreamForeignObject(InstreamForeignObject ifo) {
startElementWithIDAndAltText(ifo);
}

@Override
public void endInstreamForeignObject(InstreamForeignObject ifo) {
endElement(ifo);
}

@Override
public void startFootnote(Footnote footnote) {
startElement(footnote);
}

@Override
public void endFootnote(Footnote footnote) {
endElement(footnote);
}

@Override
public void startFootnoteBody(FootnoteBody body) {
startElement(body);
}

@Override
public void endFootnoteBody(FootnoteBody body) {
endElement(body);
}

@Override
public void startWrapper(Wrapper wrapper) {
startElement(wrapper);
}

@Override
public void endWrapper(Wrapper wrapper) {
endElement(wrapper);
}

@Override
public void character(Character c) {
startElementWithID(c);
endElement(c);
}


private void startElement(FONode node) {
startElement(node, new AttributesImpl());
}

private void startElementWithID(FONode node) {
startElementWithID(node, new AttributesImpl());
}

private void startElementWithIDAndAltText(AbstractGraphics node) {
AttributesImpl attributes = new AttributesImpl();
addAttribute(attributes, ExtensionElementMapping.URI, "alt-text",
ExtensionElementMapping.STANDARD_PREFIX, node.getAltText());
startElementWithID(node, attributes);
}

private void startElementWithID(FONode node, AttributesImpl attributes) {
String id = Integer.toHexString(idCounter++);
node.setPtr(id);
addAttribute(attributes,
InternalElementMapping.URI, "ptr", InternalElementMapping.STANDARD_PREFIX, id);
startElement(node, attributes);
}

private void startElement(FONode node, AttributesImpl attributes) {
String localName = node.getLocalName();
if (node instanceof CommonAccessibilityHolder) {
addRole((CommonAccessibilityHolder) node, attributes);
}
structureTreeEventHandler.startNode(localName, attributes);
}

private void addNoNamespaceAttribute(AttributesImpl attributes, String name, String value) {
attributes.addAttribute("", name, name, XMLUtil.CDATA, value);
}

private void addAttribute(AttributesImpl attributes,
String namespace, String localName, String prefix, String value) {
assert namespace.length() > 0 && prefix.length() > 0;
String qualifiedName = prefix + ":" + localName;
attributes.addAttribute(namespace, localName, qualifiedName, XMLUtil.CDATA, value);
}

private void addRole(CommonAccessibilityHolder node, AttributesImpl attributes) {
String role = node.getCommonAccessibility().getRole();
if (role != null) {
addNoNamespaceAttribute(attributes, "role", role);
}
}

private void endElement(FONode node) {
String localName = node.getLocalName();
structureTreeEventHandler.endNode(localName);
}

}
/** The descendants of some elements like fo:leader must be ignored. */
private final FOEventHandler eventSwallower = new FOEventHandler() {
};

/**
* Creates a new instance.
@@ -428,10 +86,8 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
public FO2StructureTreeConverter(StructureTreeEventHandler structureTreeEventHandler,
FOEventHandler delegate) {
super(delegate);
this.structureTreeEventHandler = structureTreeEventHandler;
this.foToStructureTreeEventAdapter = new FOToStructureTreeEventAdapter(foUserAgent);
this.converter = foToStructureTreeEventAdapter;
this.eventSwallower = new FOEventHandler(foUserAgent) { };
this.structureTreeEventTrigger = new StructureTreeEventTrigger(structureTreeEventHandler);
this.converter = structureTreeEventTrigger;
}

@Override
@@ -557,11 +213,16 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
@Override
public void startTable(Table tbl) {
converter.startTable(tbl);
tableFooterRecorders.push(null);
super.startTable(tbl);
}

@Override
public void endTable(Table tbl) {
FOEventRecorder tableFooterRecorder = tableFooterRecorders.pop();
if (tableFooterRecorder != null) {
tableFooterRecorder.replay(converter);
}
converter.endTable(tbl);
super.endTable(tbl);
}
@@ -592,6 +253,8 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {

@Override
public void startFooter(TableFooter footer) {
converters.push(converter);
converter = new FOEventRecorder();
converter.startFooter(footer);
super.startFooter(footer);
}
@@ -599,6 +262,10 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
@Override
public void endFooter(TableFooter footer) {
converter.endFooter(footer);
/* Replace the dummy table footer with the real one. */
tableFooterRecorders.pop();
tableFooterRecorders.push((FOEventRecorder) converter);
converter = converters.pop();
super.endFooter(footer);
}

@@ -772,6 +439,7 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {

@Override
public void startLeader(Leader l) {
converters.push(converter);
converter = eventSwallower;
converter.startLeader(l);
super.startLeader(l);
@@ -780,7 +448,7 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
@Override
public void endLeader(Leader l) {
converter.endLeader(l);
converter = foToStructureTreeEventAdapter;
converter = converters.pop();
super.endLeader(l);
}

@@ -803,9 +471,9 @@ public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
}

@Override
public void characters(char[] data, int start, int length) {
converter.characters(data, start, length);
super.characters(data, start, length);
public void characters(FOText foText) {
converter.characters(foText);
super.characters(foText);
}

@Override

+ 508
- 0
src/java/org/apache/fop/accessibility/fo/FOEventRecorder.java View File

@@ -0,0 +1,508 @@
/*
* 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.accessibility.fo;

import java.util.ArrayList;
import java.util.List;

import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.flow.ExternalGraphic;
import org.apache.fop.fo.flow.Footnote;
import org.apache.fop.fo.flow.FootnoteBody;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InstreamForeignObject;
import org.apache.fop.fo.flow.Leader;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fo.flow.PageNumberCitation;
import org.apache.fop.fo.flow.PageNumberCitationLast;
import org.apache.fop.fo.flow.Wrapper;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableBody;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;

final class FOEventRecorder extends FOEventHandler {

private interface Event {
void replay(FOEventHandler target);
}

private final List<Event> events = new ArrayList<Event>();

public void replay(FOEventHandler target) {
for (Event event : events) {
event.replay(target);
}
}

@Override
public void startPageNumber(final PageNumber pagenum) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumber(pagenum);
}
});
}

@Override
public void endPageNumber(final PageNumber pagenum) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumber(pagenum);
}
});
}

@Override
public void startPageNumberCitation(final PageNumberCitation pageCite) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumberCitation(pageCite);
}
});
}

@Override
public void endPageNumberCitation(final PageNumberCitation pageCite) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumberCitation(pageCite);
}
});
}

@Override
public void startPageNumberCitationLast(final PageNumberCitationLast pageLast) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startPageNumberCitationLast(pageLast);
}
});
}

@Override
public void endPageNumberCitationLast(final PageNumberCitationLast pageLast) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endPageNumberCitationLast(pageLast);
}
});
}

@Override
public void startBlock(final Block bl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBlock(bl);
}
});
}

@Override
public void endBlock(final Block bl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBlock(bl);
}
});
}

@Override
public void startBlockContainer(final BlockContainer blc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBlockContainer(blc);
}
});
}

@Override
public void endBlockContainer(final BlockContainer blc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBlockContainer(blc);
}
});
}

@Override
public void startInline(final Inline inl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startInline(inl);
}
});
}

@Override
public void endInline(final Inline inl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endInline(inl);
}
});
}

@Override
public void startTable(final Table tbl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startTable(tbl);
}
});
}

@Override
public void endTable(final Table tbl) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endTable(tbl);
}
});
}

@Override
public void startColumn(final TableColumn tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startColumn(tc);
}
});
}

@Override
public void endColumn(final TableColumn tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endColumn(tc);
}
});
}

@Override
public void startHeader(final TableHeader header) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startHeader(header);
}
});
}

@Override
public void endHeader(final TableHeader header) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endHeader(header);
}
});
}

@Override
public void startFooter(final TableFooter footer) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFooter(footer);
}
});
}

@Override
public void endFooter(final TableFooter footer) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFooter(footer);
}
});
}

@Override
public void startBody(final TableBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startBody(body);
}
});
}

@Override
public void endBody(final TableBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endBody(body);
}
});
}

@Override
public void startRow(final TableRow tr) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startRow(tr);
}
});
}

@Override
public void endRow(final TableRow tr) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endRow(tr);
}
});
}

@Override
public void startCell(final TableCell tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startCell(tc);
}
});
}

@Override
public void endCell(final TableCell tc) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endCell(tc);
}
});
}

@Override
public void startList(final ListBlock lb) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startList(lb);
}
});
}

@Override
public void endList(final ListBlock lb) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endList(lb);
}
});
}

@Override
public void startListItem(final ListItem li) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListItem(li);
}
});
}

@Override
public void endListItem(final ListItem li) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListItem(li);
}
});
}

@Override
public void startListLabel(final ListItemLabel listItemLabel) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListLabel(listItemLabel);
}
});
}

@Override
public void endListLabel(final ListItemLabel listItemLabel) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListLabel(listItemLabel);
}
});
}

@Override
public void startListBody(final ListItemBody listItemBody) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startListBody(listItemBody);
}
});
}

@Override
public void endListBody(final ListItemBody listItemBody) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endListBody(listItemBody);
}
});
}

@Override
public void startLink(final BasicLink basicLink) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startLink(basicLink);
}
});
}

@Override
public void endLink(final BasicLink basicLink) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endLink(basicLink);
}
});
}

@Override
public void image(final ExternalGraphic eg) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.image(eg);
}
});
}

@Override
public void startInstreamForeignObject(final InstreamForeignObject ifo) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startInstreamForeignObject(ifo);
}
});
}

@Override
public void endInstreamForeignObject(final InstreamForeignObject ifo) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endInstreamForeignObject(ifo);
}
});
}

@Override
public void startFootnote(final Footnote footnote) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFootnote(footnote);
}
});
}

@Override
public void endFootnote(final Footnote footnote) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFootnote(footnote);
}
});
}

@Override
public void startFootnoteBody(final FootnoteBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startFootnoteBody(body);
}
});
}

@Override
public void endFootnoteBody(final FootnoteBody body) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endFootnoteBody(body);
}
});
}

@Override
public void startLeader(final Leader l) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startLeader(l);
}
});
}

@Override
public void endLeader(final Leader l) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endLeader(l);
}
});
}

@Override
public void startWrapper(final Wrapper wrapper) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.startWrapper(wrapper);
}
});
}

@Override
public void endWrapper(final Wrapper wrapper) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.endWrapper(wrapper);
}
});
}

@Override
public void character(final Character c) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.character(c);
}
});
}

@Override
public void characters(final FOText foText) {
events.add(new Event() {
public void replay(FOEventHandler target) {
target.characters(foText);
}
});
}

}

+ 408
- 0
src/java/org/apache/fop/accessibility/fo/StructureTreeEventTrigger.java View File

@@ -0,0 +1,408 @@
/*
* 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.accessibility.fo;

import java.util.Locale;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.flow.AbstractGraphics;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.flow.ExternalGraphic;
import org.apache.fop.fo.flow.Footnote;
import org.apache.fop.fo.flow.FootnoteBody;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InstreamForeignObject;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fo.flow.PageNumberCitation;
import org.apache.fop.fo.flow.PageNumberCitationLast;
import org.apache.fop.fo.flow.Wrapper;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableBody;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableFooter;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fo.properties.CommonAccessibilityHolder;
import org.apache.fop.util.XMLUtil;

/**
* A bridge between {@link FOEventHandler} and {@link StructureTreeEventHandler}.
*/
class StructureTreeEventTrigger extends FOEventHandler {

private StructureTreeEventHandler structureTreeEventHandler;

public StructureTreeEventTrigger(StructureTreeEventHandler structureTreeEventHandler) {
this.structureTreeEventHandler = structureTreeEventHandler;
}

@Override
public void startDocument() throws SAXException {
}

@Override
public void endDocument() throws SAXException {
}

@Override
public void startPageSequence(PageSequence pageSeq) {
Locale locale = null;
if (pageSeq.getLanguage() != null) {
if (pageSeq.getCountry() != null) {
locale = new Locale(pageSeq.getLanguage(), pageSeq.getCountry());
} else {
locale = new Locale(pageSeq.getLanguage());
}
}
structureTreeEventHandler.startPageSequence(locale);
}

@Override
public void endPageSequence(PageSequence pageSeq) {
structureTreeEventHandler.endPageSequence();
}

@Override
public void startPageNumber(PageNumber pagenum) {
startElementWithID(pagenum);
}

@Override
public void endPageNumber(PageNumber pagenum) {
endElement(pagenum);
}

@Override
public void startPageNumberCitation(PageNumberCitation pageCite) {
startElementWithID(pageCite);
}

@Override
public void endPageNumberCitation(PageNumberCitation pageCite) {
endElement(pageCite);
}

@Override
public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
startElementWithID(pageLast);
}

@Override
public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
endElement(pageLast);
}

@Override
public void startFlow(Flow fl) {
startElement(fl);
}

@Override
public void endFlow(Flow fl) {
endElement(fl);
}

@Override
public void startBlock(Block bl) {
startElement(bl);
}

@Override
public void endBlock(Block bl) {
endElement(bl);
}

@Override
public void startBlockContainer(BlockContainer blc) {
startElement(blc);
}

@Override
public void endBlockContainer(BlockContainer blc) {
endElement(blc);
}

@Override
public void startInline(Inline inl) {
startElement(inl);
}

@Override
public void endInline(Inline inl) {
endElement(inl);
}

@Override
public void startTable(Table tbl) {
startElement(tbl);
}

@Override
public void endTable(Table tbl) {
endElement(tbl);
}

@Override
public void startHeader(TableHeader header) {
startElement(header);
}

@Override
public void endHeader(TableHeader header) {
endElement(header);
}

@Override
public void startFooter(TableFooter footer) {
startElement(footer);
}

@Override
public void endFooter(TableFooter footer) {
endElement(footer);
}

@Override
public void startBody(TableBody body) {
startElement(body);
}

@Override
public void endBody(TableBody body) {
endElement(body);
}

@Override
public void startRow(TableRow tr) {
startElement(tr);
}

@Override
public void endRow(TableRow tr) {
endElement(tr);
}

@Override
public void startCell(TableCell tc) {
AttributesImpl attributes = new AttributesImpl();
int colSpan = tc.getNumberColumnsSpanned();
if (colSpan > 1) {
addNoNamespaceAttribute(attributes, "number-columns-spanned",
Integer.toString(colSpan));
}
startElement(tc, attributes);
}

@Override
public void endCell(TableCell tc) {
endElement(tc);
}

@Override
public void startList(ListBlock lb) {
startElement(lb);
}

@Override
public void endList(ListBlock lb) {
endElement(lb);
}

@Override
public void startListItem(ListItem li) {
startElement(li);
}

@Override
public void endListItem(ListItem li) {
endElement(li);
}

@Override
public void startListLabel(ListItemLabel listItemLabel) {
startElement(listItemLabel);
}

@Override
public void endListLabel(ListItemLabel listItemLabel) {
endElement(listItemLabel);
}

@Override
public void startListBody(ListItemBody listItemBody) {
startElement(listItemBody);
}

@Override
public void endListBody(ListItemBody listItemBody) {
endElement(listItemBody);
}

@Override
public void startStatic(StaticContent staticContent) {
startElement(staticContent);
}

@Override
public void endStatic(StaticContent statisContent) {
endElement(statisContent);
}

@Override
public void startLink(BasicLink basicLink) {
startElementWithID(basicLink);
}

@Override
public void endLink(BasicLink basicLink) {
endElement(basicLink);
}

@Override
public void image(ExternalGraphic eg) {
startElementWithIDAndAltText(eg);
endElement(eg);
}

@Override
public void startInstreamForeignObject(InstreamForeignObject ifo) {
startElementWithIDAndAltText(ifo);
}

@Override
public void endInstreamForeignObject(InstreamForeignObject ifo) {
endElement(ifo);
}

@Override
public void startFootnote(Footnote footnote) {
startElement(footnote);
}

@Override
public void endFootnote(Footnote footnote) {
endElement(footnote);
}

@Override
public void startFootnoteBody(FootnoteBody body) {
startElement(body);
}

@Override
public void endFootnoteBody(FootnoteBody body) {
endElement(body);
}

@Override
public void startWrapper(Wrapper wrapper) {
startElement(wrapper);
}

@Override
public void endWrapper(Wrapper wrapper) {
endElement(wrapper);
}

@Override
public void character(Character c) {
startElementWithID(c);
endElement(c);
}

@Override
public void characters(FOText foText) {
startElementWithID(foText);
endElement(foText);
}


private void startElement(FONode node) {
startElement(node, new AttributesImpl());
}

private void startElementWithID(FONode node) {
AttributesImpl attributes = new AttributesImpl();
String localName = node.getLocalName();
if (node instanceof CommonAccessibilityHolder) {
addRole((CommonAccessibilityHolder) node, attributes);
}
node.setStructureTreeElement(structureTreeEventHandler.startReferencedNode(localName, attributes));
}

private void startElementWithIDAndAltText(AbstractGraphics node) {
AttributesImpl attributes = new AttributesImpl();
String localName = node.getLocalName();
addRole(node, attributes);
addAttribute(attributes, ExtensionElementMapping.URI, "alt-text",
ExtensionElementMapping.STANDARD_PREFIX, node.getAltText());
node.setStructureTreeElement(structureTreeEventHandler.startImageNode(localName, attributes));
}

private StructureTreeElement startElement(FONode node, AttributesImpl attributes) {
String localName = node.getLocalName();
if (node instanceof CommonAccessibilityHolder) {
addRole((CommonAccessibilityHolder) node, attributes);
}
return structureTreeEventHandler.startNode(localName, attributes);
}

private void addNoNamespaceAttribute(AttributesImpl attributes, String name, String value) {
attributes.addAttribute("", name, name, XMLUtil.CDATA, value);
}

private void addAttribute(AttributesImpl attributes,
String namespace, String localName, String prefix, String value) {
assert namespace.length() > 0 && prefix.length() > 0;
String qualifiedName = prefix + ":" + localName;
attributes.addAttribute(namespace, localName, qualifiedName, XMLUtil.CDATA, value);
}

private void addRole(CommonAccessibilityHolder node, AttributesImpl attributes) {
String role = node.getCommonAccessibility().getRole();
if (role != null) {
addNoNamespaceAttribute(attributes, "role", role);
}
}

private void endElement(FONode node) {
String localName = node.getLocalName();
structureTreeEventHandler.endNode(localName);
}

}

+ 0
- 11
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -728,7 +728,6 @@ public class AreaTreeParser {
setTraits(attributes, ip, SUBSET_BOX);
setTraits(attributes, ip, SUBSET_COLOR);
setTraits(attributes, ip, SUBSET_LINK);
setPtr(ip, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(ip);
areaStack.push(ip);
@@ -777,7 +776,6 @@ public class AreaTreeParser {
"tlsadjust", 0));
text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes,
"twsadjust", 0));
setPtr(text, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(text);
areaStack.push(text);
@@ -870,7 +868,6 @@ public class AreaTreeParser {
viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos"));
viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false));
viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0));
setPtr(viewport, attributes);
Area parent = (Area)areaStack.peek();
parent.addChildArea(viewport);
areaStack.push(viewport);
@@ -889,7 +886,6 @@ public class AreaTreeParser {
transferForeignObjects(attributes, image);
setAreaAttributes(attributes, image);
setTraits(attributes, image, SUBSET_COMMON);
setPtr(image, attributes);
getCurrentViewport().setContent(image);
}
}
@@ -1174,13 +1170,6 @@ public class AreaTreeParser {
}
}

private void setPtr(Area area, Attributes attributes) {
String ptr = attributes.getValue("ptr");
if (ptr != null) {
area.addTrait(Trait.PTR, ptr);
}
}

/** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException {
if (delegate != null) {

+ 3
- 3
src/java/org/apache/fop/area/Trait.java View File

@@ -153,8 +153,8 @@ public final class Trait implements Serializable {
/** Trait for color of linethrough decorations when rendering inline parent. */
public static final Integer LINETHROUGH_COLOR = 36;

/** The ptr trait. Used for accessibility */
public static final Integer PTR = 37;
/** For navigation in the document structure. */
public static final Integer STRUCTURE_TREE_ELEMENT = 37;

/** Maximum value used by trait keys */
public static final int MAX_TRAIT_KEY = 37;
@@ -186,7 +186,7 @@ public final class Trait implements Serializable {
static {
// Create a hashmap mapping trait code to name for external representation
//put(ID_LINK, new TraitInfo("id-link", String.class));
put(PTR, new TraitInfo("ptr", String.class));
put(STRUCTURE_TREE_ELEMENT, new TraitInfo("structure-tree-element", String.class));
put(INTERNAL_LINK, new TraitInfo("internal-link", InternalLink.class));
put(EXTERNAL_LINK, new TraitInfo("external-link", ExternalLink.class));
put(FONT, new TraitInfo("font", FontTriplet.class));

+ 2
- 2
src/java/org/apache/fop/fo/DelegatingFOEventHandler.java View File

@@ -387,8 +387,8 @@ public abstract class DelegatingFOEventHandler extends FOEventHandler {
}

@Override
public void characters(char[] data, int start, int length) {
delegate.characters(data, start, length);
public void characters(FOText foText) {
delegate.characters(foText);
}

@Override

+ 6
- 4
src/java/org/apache/fop/fo/FOEventHandler.java View File

@@ -88,6 +88,10 @@ public abstract class FOEventHandler {
this.fontInfo.setEventListener(new FontEventAdapter(foUserAgent.getEventBroadcaster()));
}

/** Constructor for sub-classes that do not need an {@link FOUserAgent} instance. */
protected FOEventHandler() {
}

/**
* Returns the User Agent object associated with this FOEventHandler.
* @return the User Agent object
@@ -532,11 +536,9 @@ public abstract class FOEventHandler {

/**
* Process character data.
* @param data Array of characters to process.
* @param start Offset for characters to process.
* @param length Portion of array to process.
* @param foText text to process
*/
public void characters(char[] data, int start, int length) {
public void characters(FOText foText) {
}

/**

+ 2
- 1
src/java/org/apache/fop/fo/FONode.java View File

@@ -32,6 +32,7 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.ExtensionAttachment;
@@ -912,7 +913,7 @@ public abstract class FONode implements Cloneable {

}

public void setPtr(String ptr) {
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
throw new UnsupportedOperationException();
}


+ 17
- 16
src/java/org/apache/fop/fo/FOText.java View File

@@ -25,6 +25,7 @@ import java.util.NoSuchElementException;

import org.xml.sax.Locator;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.Block;
@@ -79,6 +80,8 @@ public class FOText extends FONode implements CharSequence {
/** Holds the text decoration values. May be null */
private CommonTextDecoration textDecoration;

private StructureTreeElement structureTreeElement;

private static final int IS_WORD_CHAR_FALSE = 0;
private static final int IS_WORD_CHAR_TRUE = 1;
private static final int IS_WORD_CHAR_MAYBE = 2;
@@ -115,25 +118,14 @@ public class FOText extends FONode implements CharSequence {
/**
* Return the array of characters for this instance.
*
* @return a char array containing the text
* @return a char sequence containing the text
*/
public char[] getCharArray() {

public CharSequence getCharSequence() {
if (this.charBuffer == null) {
return null;
}

if (this.charBuffer.hasArray()) {
return this.charBuffer.array();
}

// only if the buffer implementation has
// no accessible backing array, return a new one
char[] ca = new char[this.charBuffer.limit()];
this.charBuffer.rewind();
this.charBuffer.get(ca);
return ca;

return this.charBuffer.asReadOnlyBuffer().subSequence(0, this.charBuffer.limit());
}

/** {@inheritDoc} */
@@ -176,8 +168,7 @@ public class FOText extends FONode implements CharSequence {
/** {@inheritDoc} */
protected void endOfNode() throws FOPException {
super.endOfNode();
getFOEventHandler().characters(
this.getCharArray(), 0, this.charBuffer.limit());
getFOEventHandler().characters(this);
}

/** {@inheritDoc} */
@@ -670,4 +661,14 @@ public class FOText extends FONode implements CharSequence {
this.charBuffer.rewind();
}
}

@Override
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

}

+ 1
- 1
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -33,7 +33,7 @@ import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.accessibility.FO2StructureTreeConverter;
import org.apache.fop.accessibility.fo.FO2StructureTreeConverter;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FormattingResults;

+ 8
- 1
src/java/org/apache/fop/fo/extensions/InternalElementMapping.java View File

@@ -37,11 +37,18 @@ public class InternalElementMapping extends ElementMapping {
/** The standard XML prefix for elements and attributes in this namespace. */
public static final String STANDARD_PREFIX = "foi";

/** The "struct-id" attribute, to identify a structure tree element. */
public static final String STRUCT_ID = "struct-id";

/** The "struct-ref" attribute, to refer to a structure tree element. */
public static final String STRUCT_REF = "struct-ref";

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

static {
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("ptr");
PROPERTY_ATTRIBUTES.add(STRUCT_ID);
PROPERTY_ATTRIBUTES.add(STRUCT_REF);
}

/**

+ 8
- 7
src/java/org/apache/fop/fo/flow/AbstractGraphics.java View File

@@ -19,6 +19,7 @@

package org.apache.fop.fo.flow;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
@@ -31,7 +32,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fo.properties.StructureTreeElementHolder;

/**
* Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_instream-foreign-object">
@@ -40,7 +41,7 @@ import org.apache.fop.fo.properties.StructurePointerPropertySet;
* <code>fo:external-graphic</code></a> flow formatting objects.
*/
public abstract class AbstractGraphics extends FObj
implements GraphicsProperties, StructurePointerPropertySet, CommonAccessibilityHolder {
implements GraphicsProperties, StructureTreeElementHolder, CommonAccessibilityHolder {

// The value of properties relevant for fo:instream-foreign-object
// and external-graphics.
@@ -66,7 +67,7 @@ public abstract class AbstractGraphics extends FObj
private int textAlign;
private Length width;
private String altText;
private String ptr; // used for accessibility
private StructureTreeElement structureTreeElement;
// Unused but valid items, commented out for performance:
// private CommonAccessibility commonAccessibility;
// private CommonAural commonAural;
@@ -226,13 +227,13 @@ public abstract class AbstractGraphics extends FObj
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

public String getAltText() {

+ 8
- 7
src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java View File

@@ -24,6 +24,7 @@ import java.awt.Color;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
@@ -37,7 +38,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fo.properties.StructureTreeElementHolder;

/**
* Common base class for the <a href="http://www.w3.org/TR/xsl/#fo_page-number-citation">
@@ -46,7 +47,7 @@ import org.apache.fop.fo.properties.StructurePointerPropertySet;
* <code>fo:page-number-citation-last</code></a> objects.
*/
public abstract class AbstractPageNumberCitation extends FObj
implements StructurePointerPropertySet, CommonAccessibilityHolder {
implements StructureTreeElementHolder, CommonAccessibilityHolder {

// The value of properties relevant for fo:page-number-citation(-last).
private CommonAccessibility commonAccessibility;
@@ -56,7 +57,7 @@ public abstract class AbstractPageNumberCitation extends FObj
private int alignmentBaseline;
private Length baselineShift;
private int dominantBaseline;
private String ptr; // used for accessibility
private StructureTreeElement structureTreeElement;
// private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight;
private String refId;
@@ -151,13 +152,13 @@ public abstract class AbstractPageNumberCitation extends FObj
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

/** @return the "alignment-adjust" property */

+ 8
- 7
src/java/org/apache/fop/fo/flow/BasicLink.java View File

@@ -21,12 +21,13 @@ package org.apache.fop.fo.flow;

import org.xml.sax.Locator;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fo.properties.StructureTreeElementHolder;

/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_basic-link">
@@ -36,14 +37,14 @@ import org.apache.fop.fo.properties.StructurePointerPropertySet;
* and whether that link is external (uses a URI) or internal (an id
* reference).
*/
public class BasicLink extends InlineLevel implements StructurePointerPropertySet {
public class BasicLink extends InlineLevel implements StructureTreeElementHolder {

// The value of properties relevant for fo:basic-link.
private Length alignmentAdjust;
private int alignmentBaseline;
private Length baselineShift;
private int dominantBaseline;
private String ptr;
private StructureTreeElement structureTreeElement;
// private ToBeImplementedProperty destinationPlacementOffset;
private String externalDestination;
// private ToBeImplementedProperty indicateDestination;
@@ -143,13 +144,13 @@ public class BasicLink extends InlineLevel implements StructurePointerPropertySe
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

/**

+ 1
- 13
src/java/org/apache/fop/fo/flow/Block.java View File

@@ -42,13 +42,12 @@ import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;

/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_block">
* <code>fo:block object</code></a>.
*/
public class Block extends FObjMixed implements BreakPropertySet, StructurePointerPropertySet,
public class Block extends FObjMixed implements BreakPropertySet,
CommonAccessibilityHolder {

// used for FO validation
@@ -77,7 +76,6 @@ public class Block extends FObjMixed implements BreakPropertySet, StructurePoint
private int lineHeightShiftAdjustment;
private int lineStackingStrategy;
private Numeric orphans;
private String ptr; //used for accessibility
private int whiteSpaceTreatment;
private int span;
private int textAlign;
@@ -183,16 +181,6 @@ public class Block extends FObjMixed implements BreakPropertySet, StructurePoint
return breakAfter;
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** @return the "break-before" property. */
public int getBreakBefore() {
return breakBefore;

+ 8
- 7
src/java/org/apache/fop/fo/flow/Character.java View File

@@ -24,6 +24,7 @@ import java.util.NoSuchElementException;

import org.xml.sax.Locator;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.CharIterator;
@@ -38,13 +39,13 @@ import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fo.properties.StructureTreeElementHolder;

/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_character">
* <code>fo:character</code></a> object.
*/
public class Character extends FObj implements StructurePointerPropertySet {
public class Character extends FObj implements StructureTreeElementHolder {
// The value of properties relevant for fo:character.
private CommonBorderPaddingBackground commonBorderPaddingBackground;
private CommonFont commonFont;
@@ -63,7 +64,7 @@ public class Character extends FObj implements StructurePointerPropertySet {
private CommonTextDecoration textDecoration;
// private ToBeImplementedProperty textShadow;
private Property wordSpacing;
private String ptr; // used for accessibility
private StructureTreeElement structureTreeElement;
// Unused but valid items, commented out for performance:
// private CommonAural commonAural;
// private CommonMarginInline commonMarginInline;
@@ -210,13 +211,13 @@ public class Character extends FObj implements StructurePointerPropertySet {
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

/** {@inheritDoc} */

+ 1
- 13
src/java/org/apache/fop/fo/flow/Inline.java View File

@@ -26,19 +26,17 @@ import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.StructurePointerPropertySet;

/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_inline">
* <code>fo:inline</code></a> formatting object.
*/
public class Inline extends InlineLevel implements StructurePointerPropertySet {
public class Inline extends InlineLevel {
// The value of properties relevant for fo:inline.
// See also superclass InlineLevel
private Length alignmentAdjust;
private int alignmentBaseline;
private Length baselineShift;
private String ptr; // used for accessibility
private int dominantBaseline;
// Unused but valid items, commented out for performance:
// private CommonRelativePosition commonRelativePosition;
@@ -147,16 +145,6 @@ public class Inline extends InlineLevel implements StructurePointerPropertySet {
return dominantBaseline;
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/** {@inheritDoc} */
public String getLocalName() {
return "inline";

+ 8
- 7
src/java/org/apache/fop/fo/flow/PageNumber.java View File

@@ -23,6 +23,7 @@ import java.awt.Color;

import org.xml.sax.Locator;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.Constants;
@@ -36,14 +37,14 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonFont;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fo.properties.StructureTreeElementHolder;

/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_page-number">
* <code>fo:page-number</code></a> object.
*/
public class PageNumber extends FObj
implements StructurePointerPropertySet, CommonAccessibilityHolder {
implements StructureTreeElementHolder, CommonAccessibilityHolder {
// The value of properties relevant for fo:page-number.
private CommonAccessibility commonAccessibility;
private CommonBorderPaddingBackground commonBorderPaddingBackground;
@@ -52,7 +53,7 @@ public class PageNumber extends FObj
private int alignmentBaseline;
private Length baselineShift;
private int dominantBaseline;
private String ptr; // used for accessibility
private StructureTreeElement structureTreeElement;
// private ToBeImplementedProperty letterSpacing;
private SpaceProperty lineHeight;
/** Holds the text decoration values. May be null */
@@ -176,13 +177,13 @@ public class PageNumber extends FObj
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

/** {@inheritDoc} */

+ 1
- 13
src/java/org/apache/fop/fo/flow/table/TableFObj.java View File

@@ -36,19 +36,17 @@ import org.apache.fop.fo.properties.EnumProperty;
import org.apache.fop.fo.properties.NumberProperty;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.layoutmgr.table.CollapsingBorderModel;

/**
* Common base class for table-related FOs
*/
public abstract class TableFObj extends FObj implements StructurePointerPropertySet {
public abstract class TableFObj extends FObj {

private Numeric borderAfterPrecedence;
private Numeric borderBeforePrecedence;
private Numeric borderEndPrecedence;
private Numeric borderStartPrecedence;
private String ptr;

ConditionalBorder borderBefore; // CSOK: VisibilityModifier
ConditionalBorder borderAfter; // CSOK: VisibilityModifier
@@ -240,16 +238,6 @@ public abstract class TableFObj extends FObj implements StructurePointerProperty
}
}

@Override
public void setPtr(String ptr) {
this.ptr = ptr;
}

/** {@inheritDoc} */
public String getPtr() {
return ptr;
}

/**
* Prepares the borders of this element if the collapsing-border model is in use.
* Conflict resolution with parent elements is done where applicable.

+ 38
- 0
src/java/org/apache/fop/fo/properties/StructureTreeElementHolder.java View File

@@ -0,0 +1,38 @@
/*
* 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.fo.properties;

import org.apache.fop.accessibility.StructureTreeElement;

/**
* Implementations of this interface can return the element in the document's
* structure tree that they resulted into. Used for tagged PDF and other formats
* that support a structure tree in addition to paged content.
*/
public interface StructureTreeElementHolder {

/**
* Returns the element in the document's structure tree that corresponds to this instance.
*
* @return a structure tree element
*/
StructureTreeElement getStructureTreeElement();

}

+ 0
- 1
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

@@ -329,7 +329,6 @@ public class BlockLayoutManager extends BlockStackingLayoutManager

addMarkersToPage(false, isFirst(firstPos), isLast(lastPos));

TraitSetter.addPtr(curBlockArea, getBlockFO().getPtr()); // used for accessibility
TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(),
effSpaceBefore, effSpaceAfter);
flush();

+ 8
- 6
src/java/org/apache/fop/layoutmgr/TraitSetter.java View File

@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.area.Area;
import org.apache.fop.area.Trait;
import org.apache.fop.datatypes.LengthBase;
@@ -29,9 +30,9 @@ import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.datatypes.SimplePercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.fo.properties.CommonMarginBlock;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.fonts.Font;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.MinOptMax;
@@ -591,13 +592,14 @@ public final class TraitSetter {
}

/**
* Adds the ptr trait to the area.
* Sets the structure tree element associated to the given area.
*
* @param area the area to set the traits on
* @param ptr string
* @param structureTreeElement the element the area is associated to in the document structure
*/
public static void addPtr(Area area, String ptr) {
if (ptr != null && ptr.length() > 0) {
area.addTrait(Trait.PTR, ptr);
public static void addStructureTreeElement(Area area, StructureTreeElement structureTreeElement) {
if (structureTreeElement != null) {
area.addTrait(Trait.STRUCTURE_TREE_ELEMENT, structureTreeElement);
}
}


+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java View File

@@ -85,7 +85,7 @@ public abstract class AbstractGraphicsLayoutManager extends LeafNodeLayoutManage
transferForeignAttributes(viewportArea);

InlineViewport vp = new InlineViewport(viewportArea);
TraitSetter.addPtr(vp, fobj.getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(vp, fobj.getStructureTreeElement());
TraitSetter.setProducerID(vp, fobj.getId());
vp.setIPD(imageLayout.getViewportSize().width);
vp.setBPD(imageLayout.getViewportSize().height);

+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java View File

@@ -136,7 +136,7 @@ public abstract class AbstractPageNumberCitationLayoutManager extends LeafNodeLa
text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(text, fobj.getStructureTreeElement());
TraitSetter.addTextDecoration(text, fobj.getTextDecoration());
}


+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java View File

@@ -59,7 +59,7 @@ public class BasicLinkLayoutManager extends InlineLayoutManager {
private void setupBasicLinkArea(InlineArea area) {
BasicLink fobj = (BasicLink) this.fobj;
// internal destinations take precedence:
TraitSetter.addPtr(area, fobj.getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(area, fobj.getStructureTreeElement());
if (fobj.hasInternalDestination()) {
String idref = fobj.getInternalDestination();
PageSequenceLayoutManager pslm = getPSLM();

+ 1
- 1
src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java View File

@@ -87,7 +87,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
}
TraitSetter.setProducerID(text, node.getId());
TraitSetter.addTextDecoration(text, node.getTextDecoration());
TraitSetter.addPtr(text, node.getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(text, node.getStructureTreeElement());
return text;
}


+ 4
- 4
src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java View File

@@ -19,13 +19,13 @@

package org.apache.fop.layoutmgr.inline;

import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.flow.PageNumber;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.area.Trait;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.traits.MinOptMax;
@@ -85,7 +85,7 @@ public class PageNumberLayoutManager extends LeafNodeLayoutManager {
text.setBaselineOffset(font.getAscender());
TraitSetter.addFontTraits(text, font);
text.addTrait(Trait.COLOR, fobj.getColor());
TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(text, fobj.getStructureTreeElement());
TraitSetter.addTextDecoration(text, fobj.getTextDecoration());

return text;

+ 1
- 17
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java View File

@@ -31,8 +31,6 @@ import org.apache.fop.area.Trait;
import org.apache.fop.area.inline.TextArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.StructurePointerPropertySet;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontSelector;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
@@ -438,7 +436,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
setText();
TraitSetter.addFontTraits(textArea, font);
textArea.addTrait(Trait.COLOR, foText.getColor());
TraitSetter.addPtr(textArea, getPtr()); // used for accessibility
TraitSetter.addStructureTreeElement(textArea, foText.getStructureTreeElement());
TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
TraitSetter.addFontTraits(textArea, font);
return textArea;
@@ -577,20 +575,6 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
}
}

/**
* used for accessibility
* @return ptr of fobj
*/
private String getPtr() {
FObj fobj = parentLayoutManager.getFObj();
if (fobj instanceof StructurePointerPropertySet) {
return (((StructurePointerPropertySet) fobj).getPtr());
} else {
//No structure pointer applicable
return null;
}
}

private AreaInfo getAreaInfo(int index) {
return (AreaInfo) areaInfos.get(index);
}

+ 73
- 29
src/java/org/apache/fop/pdf/PDFStructElem.java View File

@@ -19,17 +19,28 @@

package org.apache.fop.pdf;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.util.LanguageTags;

/**
* Class representing a PDF Structure Element.
*/
public class PDFStructElem extends PDFDictionary {
public class PDFStructElem extends PDFDictionary implements StructureTreeElement {

private PDFStructElem parentElement;

/**
* Elements to be added to the kids array.
*/
protected List<PDFObject> kids;

/**
* Creates a new structure element.
*
@@ -57,20 +68,11 @@ public class PDFStructElem extends PDFDictionary {

/** {@inheritDoc} */
public void setParent(PDFObject parent) {
if (parent != null) {
if (parent != null && parent.hasObjectNumber()) {
put("P", new PDFReference(parent));
}
}

/**
* Returns the kids of this structure element.
*
* @return the value of the K entry
*/
private PDFArray getKids() {
return (PDFArray) get("K");
}

/**
* Add a kid to this structure element. This element will then add itself to
* its parent structure element if it has not already, and so will the
@@ -79,24 +81,10 @@ public class PDFStructElem extends PDFDictionary {
* @param kid element to be added
*/
public void addKid(PDFObject kid) {
PDFArray kids = getKids();
if (kids == null) {
kids = new PDFArray();
put("K", kids);
kids = new ArrayList<PDFObject>();
}
kids.add(kid);
joinHierarchy();
}

private boolean containsKid(PDFObject kid) {
PDFArray kids = getKids();
return kids != null && kids.contains(kid);
}

private void joinHierarchy() {
if (parentElement != null && !parentElement.containsKid(this)) {
parentElement.addKid(this);
}
}

/**
@@ -109,7 +97,6 @@ public class PDFStructElem extends PDFDictionary {
*/
public void setMCIDKid(int mcid) {
put("K", mcid);
joinHierarchy();
}

/**
@@ -127,7 +114,7 @@ public class PDFStructElem extends PDFDictionary {
* @return the value of the S entry
*/
public PDFName getStructureType() {
return (PDFName)get("S");
return (PDFName) get("S");
}

/**
@@ -154,6 +141,63 @@ public class PDFStructElem extends PDFDictionary {
* @return the value of the Lang entry (<code>null</code> if no language was specified)
*/
public String getLanguage() {
return (String)get("Lang");
return (String) get("Lang");
}

@Override
protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
attachKids();
super.writeDictionary(out, writer);
}

/**
* Attaches all valid kids to the kids array.
*
* @return true iff 1+ kids were added to the kids array
*/
protected boolean attachKids() {
List<PDFObject> validKids = new ArrayList<PDFObject>();
if (kids != null) {
for (PDFObject kid : kids) {
if (kid instanceof Placeholder) {
if (((Placeholder) kid).attachKids()) {
validKids.add(kid);
}
} else {
validKids.add(kid);
}
}
}
boolean kidsAttached = !validKids.isEmpty();
if (kidsAttached) {
PDFArray array = new PDFArray();
for (PDFObject ob : validKids) {
array.add(ob);
}
put("K", array);
}
return kidsAttached;
}

public static class Placeholder extends PDFStructElem {

@Override
public void outputInline(OutputStream out, Writer writer) throws IOException {
if (kids != null) {
assert kids.size() > 0;
for (int i = 0; i < kids.size(); i++) {
if (i > 0) {
writer.write(' ');
}
Object obj = kids.get(i);
formatObject(obj, out, writer);
}
}
}

public Placeholder(PDFObject parent, String name) {
super(parent, new PDFName(name));
}
}

}

+ 18
- 15
src/java/org/apache/fop/render/intermediate/IFContext.java View File

@@ -25,6 +25,7 @@ import java.util.Map;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOUserAgent;

/**
@@ -46,7 +47,7 @@ public class IFContext {

private Locale language;

private String structurePointer;
private StructureTreeElement structureTreeElement;

private String id = "";

@@ -132,29 +133,31 @@ public class IFContext {
}

/**
* Sets the structure pointer for the following painted marks. This method is used when
* accessibility features are enabled.
* @param ptr the structure pointer
* Sets the structure tree element to which the subsequently painted marks
* will correspond. This method is used when accessibility features are
* enabled.
*
* @param structureTreeElement the structure tree element
*/
public void setStructurePointer(String ptr) {
this.structurePointer = ptr;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/**
* Resets the current structure pointer.
* @see #setStructurePointer(String)
* Resets the current structure tree element.
* @see #setStructureTreeElement(String)
*/
public void resetStructurePointer() {
setStructurePointer(null);
public void resetStructureTreeElement() {
setStructureTreeElement(null);
}

/**
* Returns the current structure pointer.
* @return the structure pointer (or null if no pointer is active)
* @see #setStructurePointer(String)
* Returns the current structure tree element.
* @return the structure tree element (or null if no element is active)
* @see #setStructureTreeElement(String)
*/
public String getStructurePointer() {
return this.structurePointer;
public StructureTreeElement getStructureTreeElement() {
return this.structureTreeElement;
}

/**

+ 38
- 18
src/java/org/apache/fop/render/intermediate/IFParser.java View File

@@ -49,11 +49,13 @@ import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.util.QName;

import org.apache.fop.accessibility.AccessibilityEventProducer;
import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.render.intermediate.extensions.DocumentNavigationExtensionConstants;
import org.apache.fop.render.intermediate.extensions.DocumentNavigationHandler;
import org.apache.fop.traits.BorderProps;
@@ -158,6 +160,9 @@ public class IFParser implements IFConstants {

private Attributes pageSequenceAttributes;

private Map<String, StructureTreeElement> structureTreeElements =
new HashMap<String, StructureTreeElement>();

private final class StructureTreeHandler extends DefaultHandler {

private final StructureTreeEventHandler structureTreeEventHandler;
@@ -177,7 +182,23 @@ public class IFParser implements IFConstants {
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (!"structure-tree".equals(localName)) {
structureTreeEventHandler.startNode(localName, attributes);
if (localName.equals("marked-content")) {
localName = "#PCDATA";
}
String structID = attributes.getValue(InternalElementMapping.URI,
InternalElementMapping.STRUCT_ID);
if (structID == null) {
structureTreeEventHandler.startNode(localName, attributes);
} else if (localName.equals("external-graphic")
|| localName.equals("instream-foreign-object")) {
StructureTreeElement structureTreeElement =
structureTreeEventHandler.startImageNode(localName, attributes);
structureTreeElements.put(structID, structureTreeElement);
} else {
StructureTreeElement structureTreeElement =
structureTreeEventHandler.startReferencedNode(localName, attributes);
structureTreeElements.put(structID, structureTreeElement);
}
}
}

@@ -225,14 +246,6 @@ public class IFParser implements IFConstants {
documentHandler.getContext().resetForeignAttributes();
}

private void establishStructurePointer(String ptr) {
documentHandler.getContext().setStructurePointer(ptr);
}

private void resetStructurePointer() {
documentHandler.getContext().resetStructurePointer();
}

/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
@@ -276,7 +289,7 @@ public class IFParser implements IFConstants {
} else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) {
if (this.navParser == null) {
this.navParser = new DocumentNavigationHandler(
this.documentHandler.getDocumentNavigationHandler());
this.documentHandler.getDocumentNavigationHandler(), structureTreeElements);
}
delegate = this.navParser;
delegateDepth++;
@@ -604,9 +617,9 @@ public class IFParser implements IFConstants {
s = lastAttributes.getValue("word-spacing");
int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
setStructurePointer(lastAttributes);
establishStructureTreeElement(lastAttributes);
painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
resetStructurePointer();
resetStructureTreeElement();
}

public boolean ignoreCharacters() {
@@ -701,7 +714,7 @@ public class IFParser implements IFConstants {
int height = Integer.parseInt(lastAttributes.getValue("height"));
Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
setStructurePointer(lastAttributes);
establishStructureTreeElement(lastAttributes);
if (foreignObject != null) {
painter.drawImage(foreignObject,
new Rectangle(x, y, width, height));
@@ -715,7 +728,7 @@ public class IFParser implements IFConstants {
painter.drawImage(uri, new Rectangle(x, y, width, height));
}
resetForeignAttributes();
resetStructurePointer();
resetStructureTreeElement();
inForeignObject = false;
}

@@ -769,13 +782,20 @@ public class IFParser implements IFConstants {
return foreignAttributes;
}

private void setStructurePointer(Attributes attributes) {
String ptr = attributes.getValue("ptr");
if (ptr != null && ptr.length() > 0) {
establishStructurePointer(ptr);
private void establishStructureTreeElement(Attributes attributes) {
String structRef = attributes.getValue(InternalElementMapping.URI,
InternalElementMapping.STRUCT_REF);
if (structRef != null && structRef.length() > 0) {
assert structureTreeElements.containsKey(structRef);
StructureTreeElement structureTreeElement = structureTreeElements.get(structRef);
documentHandler.getContext().setStructureTreeElement(structureTreeElement);
}
}

private void resetStructureTreeElement() {
documentHandler.getContext().resetStructureTreeElement();
}

/** {@inheritDoc} */
public void characters(char[] ch, int start, int length) throws SAXException {
if (delegate != null) {

+ 12
- 9
src/java/org/apache/fop/render/intermediate/IFRenderer.java View File

@@ -50,6 +50,7 @@ import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;

import org.apache.fop.Version;
import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
@@ -629,12 +630,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
documentHandler.getContext().resetForeignAttributes();
}

private void establishStructurePointer(String ptr) {
documentHandler.getContext().setStructurePointer(ptr);
private void establishStructureTreeElement(StructureTreeElement structureTreeElement) {
documentHandler.getContext().setStructureTreeElement(structureTreeElement);
}

private void resetStructurePointer() {
documentHandler.getContext().resetStructurePointer();
documentHandler.getContext().resetStructureTreeElement();
}

/** {@inheritDoc} */
@@ -851,8 +852,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

/** {@inheritDoc} */
public void renderInlineViewport(InlineViewport viewport) {
String ptr = (String) viewport.getTrait(Trait.PTR);
establishStructurePointer(ptr);
StructureTreeElement structElem =
(StructureTreeElement) viewport.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
establishStructureTreeElement(structElem);
pushdID(viewport);
Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD());
viewportDimensionStack.push(dim);
@@ -912,7 +914,6 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
// stuff we only need if a link must be created:
Rectangle ipRect = null;
AbstractAction action = null;
String ptr = (String) ip.getTrait(Trait.PTR); // used for accessibility
// make sure the rect is determined *before* calling super!
int ipp = currentIPPosition;
int bpp = currentBPPosition + ip.getOffset();
@@ -956,7 +957,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

// warn if link trait found but not allowed, else create link
if (linkTraitFound) {
action.setStructurePointer(ptr); // used for accessibility
StructureTreeElement structElem =
(StructureTreeElement) ip.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
action.setStructureTreeElement(structElem);
Link link = new Link(action, ipRect);
this.deferredLinks.add(link);
}
@@ -1009,8 +1012,8 @@ public class IFRenderer extends AbstractPathOrientedRenderer {

String fontName = getInternalFontNameForArea(text);
int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
String ptr = (String)text.getTrait(Trait.PTR); // used for accessibility
establishStructurePointer(ptr);
StructureTreeElement structElem = (StructureTreeElement) text.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
establishStructureTreeElement(structElem);

// This assumes that *all* CIDFonts use a /ToUnicode mapping
Typeface tf = getTypeface(fontName);

+ 21
- 8
src/java/org/apache/fop/render/intermediate/IFSerializer.java View File

@@ -38,9 +38,11 @@ import org.apache.xmlgraphics.util.QName;
import org.apache.xmlgraphics.util.XMLizable;

import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.intermediate.IFStructureTreeBuilder.IFStructureTreeElement;
import org.apache.fop.render.intermediate.extensions.AbstractAction;
import org.apache.fop.render.intermediate.extensions.Bookmark;
import org.apache.fop.render.intermediate.extensions.BookmarkTree;
@@ -163,6 +165,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE);
handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX,
DocumentNavigationExtensionConstants.NAMESPACE);
handler.startPrefixMapping(InternalElementMapping.STANDARD_PREFIX, InternalElementMapping.URI);
handler.startElement(EL_DOCUMENT);
} catch (SAXException e) {
throw new IFException("SAX error in startDocument()", e);
@@ -439,7 +442,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts);
addStructurePointerAttribute(atts);
addStructureReference(atts);
handler.element(EL_IMAGE, atts);
} catch (SAXException e) {
throw new IFException("SAX error in startGroup()", e);
@@ -467,7 +470,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
addAttribute(atts, "width", Integer.toString(rect.width));
addAttribute(atts, "height", Integer.toString(rect.height));
addForeignAttributes(atts);
addStructurePointerAttribute(atts);
addStructureReference(atts);
handler.startElement(EL_IMAGE, atts);
new DOM2SAX(handler).writeDocument(doc, true);
handler.endElement(EL_IMAGE);
@@ -582,7 +585,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
if (dx != null) {
addAttribute(atts, "dx", IFUtil.toString(dx));
}
addStructurePointerAttribute(atts);
addStructureReference(atts);
handler.startElement(EL_TEXT, atts);
char[] chars = text.toCharArray();
handler.characters(chars, 0, chars.length);
@@ -682,13 +685,22 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
XMLUtil.addAttribute(atts, localName, value);
}

private void addStructurePointerAttribute(AttributesImpl atts) {
String ptr = getContext().getStructurePointer();
if (ptr != null) {
addAttribute(atts, "ptr", ptr);
private void addStructureReference(AttributesImpl atts) {
IFStructureTreeElement structureTreeElement =
(IFStructureTreeElement) getContext().getStructureTreeElement();
if (structureTreeElement != null) {
addStructRefAttribute(atts, structureTreeElement.id);
}
}

private void addStructRefAttribute(AttributesImpl atts, String id) {
atts.addAttribute(InternalElementMapping.URI,
InternalElementMapping.STRUCT_REF,
InternalElementMapping.STANDARD_PREFIX + ":" + InternalElementMapping.STRUCT_REF,
XMLConstants.CDATA,
id);
}

private void addID() throws SAXException {
String id = getContext().getID();
if (!currentID.equals(id)) {
@@ -773,7 +785,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
atts.addAttribute(null, "rect", "rect",
XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
if (getUserAgent().isAccessibilityEnabled()) {
addAttribute(atts, "ptr", link.getAction().getStructurePointer());
addStructRefAttribute(atts,
((IFStructureTreeElement) link.getAction().getStructureTreeElement()).id);
}
try {
handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);

+ 81
- 37
src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java View File

@@ -26,10 +26,14 @@ import java.util.Locale;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;

import org.apache.fop.accessibility.StructureTree2SAXEventAdapter;
import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.util.XMLUtil;

/**
* Saves structure tree events as SAX events in order to replay them when it's
@@ -37,42 +41,17 @@ import org.apache.fop.accessibility.StructureTreeEventHandler;
*/
final class IFStructureTreeBuilder implements StructureTreeEventHandler {

private StructureTreeEventHandler delegate;

private final List<SAXEventRecorder> pageSequenceEventRecorders = new ArrayList<SAXEventRecorder>();

/**
* Replay SAX events for a page sequence.
* @param handler The handler that receives SAX events
* @param pageSequenceIndex The index of the page sequence
* @throws SAXException
*/
public void replayEventsForPageSequence(ContentHandler handler,
int pageSequenceIndex) throws SAXException {
pageSequenceEventRecorders.get(pageSequenceIndex).replay(handler);
}

/** {@inheritDoc} */
public void startPageSequence(Locale locale) {
SAXEventRecorder eventRecorder = new SAXEventRecorder();
pageSequenceEventRecorders.add(eventRecorder);
delegate = StructureTree2SAXEventAdapter.newInstance(eventRecorder);
delegate.startPageSequence(locale);
}
static final class IFStructureTreeElement implements StructureTreeElement {

/** {@inheritDoc} */
public void endPageSequence() {
delegate.endPageSequence();
}
final String id;

/** {@inheritDoc} */
public void startNode(String name, Attributes attributes) {
delegate.startNode(name, attributes);
}
IFStructureTreeElement() {
this.id = null;
}

/** {@inheritDoc} */
public void endNode(String name) {
delegate.endNode(name);
IFStructureTreeElement(String id) {
this.id = id;
}
}

/** A SAX handler that records events to replay them later. */
@@ -159,22 +138,22 @@ final class IFStructureTreeBuilder implements StructureTreeEventHandler {
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
events.add(new StartElement(uri, localName, qName, attributes));
};
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
events.add(new EndElement(uri, localName, qName));
};
}

@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
events.add(new StartPrefixMapping(prefix, uri));
};
}

@Override
public void endPrefixMapping(String prefix) throws SAXException {
events.add(new EndPrefixMapping(prefix));
};
}

/**
* Replays the recorded events.
@@ -187,4 +166,69 @@ final class IFStructureTreeBuilder implements StructureTreeEventHandler {
}
}
}

private StructureTreeEventHandler delegate;

private final List<SAXEventRecorder> pageSequenceEventRecorders = new ArrayList<SAXEventRecorder>();

private int idCounter;

/**
* Replay SAX events for a page sequence.
* @param handler The handler that receives SAX events
* @param pageSequenceIndex The index of the page sequence
* @throws SAXException
*/
public void replayEventsForPageSequence(ContentHandler handler,
int pageSequenceIndex) throws SAXException {
pageSequenceEventRecorders.get(pageSequenceIndex).replay(handler);
}

public void startPageSequence(Locale locale) {
SAXEventRecorder eventRecorder = new SAXEventRecorder();
pageSequenceEventRecorders.add(eventRecorder);
delegate = StructureTree2SAXEventAdapter.newInstance(eventRecorder);
delegate.startPageSequence(locale);
}

public void endPageSequence() {
delegate.endPageSequence();
}

public StructureTreeElement startNode(String name, Attributes attributes) {
delegate.startNode(name, attributes);
return new IFStructureTreeElement();
}

public void endNode(String name) {
delegate.endNode(name);
}

public StructureTreeElement startImageNode(String name, Attributes attributes) {
String id = getNextID();
AttributesImpl atts = addIDAttribute(attributes, id);
delegate.startImageNode(name, atts);
return new IFStructureTreeElement(id);
}

public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
String id = getNextID();
AttributesImpl atts = addIDAttribute(attributes, id);
delegate.startReferencedNode(name, atts);
return new IFStructureTreeElement(id);
}

private String getNextID() {
return Integer.toHexString(idCounter++);
}

private AttributesImpl addIDAttribute(Attributes attributes, String id) {
AttributesImpl atts = new AttributesImpl(attributes);
atts.addAttribute(InternalElementMapping.URI,
InternalElementMapping.STRUCT_ID,
InternalElementMapping.STANDARD_PREFIX + ":" + InternalElementMapping.STRUCT_ID,
XMLUtil.CDATA,
id);
return atts;
}
}

+ 8
- 6
src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java View File

@@ -21,13 +21,15 @@ package org.apache.fop.render.intermediate.extensions;

import org.apache.xmlgraphics.util.XMLizable;

import org.apache.fop.accessibility.StructureTreeElement;

/**
* Abstract base class for document actions, like "go-to" actions with absolute page coordinates.
*/
public abstract class AbstractAction implements XMLizable {

private String id;
private String structurePointer;
private StructureTreeElement structureTreeElement;

/**
* Sets an ID to make the action referencable.
@@ -47,18 +49,18 @@ public abstract class AbstractAction implements XMLizable {

/**
* Sets the structure element corresponding to this action.
* @param structurePointer a reference to the structure element
* @param structureTreeElement a reference to the structure element
*/
public void setStructurePointer(String structurePointer) {
this.structurePointer = structurePointer;
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}

/**
* Returns the structure element corresponding to this action.
* @return the reference to the structure element
*/
public String getStructurePointer() {
return structurePointer;
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}

/**

+ 17
- 7
src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java View File

@@ -21,6 +21,7 @@ package org.apache.fop.render.intermediate.extensions;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.Map;
import java.util.Stack;

import org.xml.sax.Attributes;
@@ -30,6 +31,8 @@ import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.util.XMLUtil;
@@ -48,14 +51,20 @@ public class DocumentNavigationHandler extends DefaultHandler

private IFDocumentNavigationHandler navHandler;

private String structurePointer;
private StructureTreeElement structureTreeElement;

private Map<String, StructureTreeElement> structureTreeElements;

/**
* Main constructor.
* @param navHandler the navigation handler that will receive the events
* @param structureTreeElements the elements representing the structure of the document
*/
public DocumentNavigationHandler(IFDocumentNavigationHandler navHandler) {
public DocumentNavigationHandler(IFDocumentNavigationHandler navHandler,
Map<String, StructureTreeElement> structureTreeElements) {
this.navHandler = navHandler;
assert structureTreeElements != null;
this.structureTreeElements = structureTreeElements;
}

/** {@inheritDoc} */
@@ -98,7 +107,8 @@ public class DocumentNavigationHandler extends DefaultHandler
throw new SAXException(localName + " must be the root element!");
}
Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect");
structurePointer = attributes.getValue("ptr");
structureTreeElement = structureTreeElements.get(
attributes.getValue(InternalElementMapping.URI, InternalElementMapping.STRUCT_REF));
Link link = new Link(null, targetRect);
objectStack.push(link);
} else if (GOTO_XY.getLocalName().equals(localName)) {
@@ -121,8 +131,8 @@ public class DocumentNavigationHandler extends DefaultHandler
}
action = new GoToXYAction(id, pageIndex, location);
}
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
if (structureTreeElement != null) {
action.setStructureTreeElement(structureTreeElement);
}
objectStack.push(action);
} else if (GOTO_URI.getLocalName().equals(localName)) {
@@ -134,8 +144,8 @@ public class DocumentNavigationHandler extends DefaultHandler
if (id != null) {
action.setID(id);
}
if (structurePointer != null) {
action.setStructurePointer(structurePointer);
if (structureTreeElement != null) {
action.setStructureTreeElement(structureTreeElement);
}
objectStack.push(action);
} else {

+ 4
- 4
src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java View File

@@ -31,6 +31,7 @@ import org.apache.fop.pdf.PDFFactory;
import org.apache.fop.pdf.PDFGoTo;
import org.apache.fop.pdf.PDFLink;
import org.apache.fop.pdf.PDFOutline;
import org.apache.fop.pdf.PDFStructElem;
import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.extensions.AbstractAction;
@@ -111,10 +112,9 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
targetRect2D, pdfAction);
if (pdfLink != null) {
String ptr = link.getAction().getStructurePointer();
if (documentHandler.getUserAgent().isAccessibilityEnabled()
&& ptr != null && ptr.length() > 0) {
documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr);
PDFStructElem structure = (PDFStructElem) link.getAction().getStructureTreeElement();
if (documentHandler.getUserAgent().isAccessibilityEnabled() && structure != null) {
documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, structure);
}
documentHandler.currentPage.addAnnotation(pdfLink);
}

+ 28
- 56
src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java View File

@@ -19,9 +19,7 @@

package org.apache.fop.render.pdf;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.apache.fop.pdf.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
@@ -47,11 +45,6 @@ class PDFLogicalStructureHandler {

private final PDFDocument pdfDoc;

/**
* Map of references to the corresponding structure elements.
*/
private final Map<String, PDFStructElem> structTreeMap = new HashMap<String, PDFStructElem>();

private final PDFParentTree parentTree = new PDFParentTree();

private int parentTreeKey;
@@ -151,100 +144,79 @@ class PDFLogicalStructureHandler {
parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray);
}

private MarkedContentInfo addToParentTree(String structurePointer) {
PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
if (parent == null) {
return ARTIFACT;
} else {
pageParentTreeArray.add(parent);
String type = parent.getStructureType().toString();
int mcid = pageParentTreeArray.length() - 1;
return new MarkedContentInfo(type, mcid, parent);
}
private MarkedContentInfo addToParentTree(PDFStructElem structureTreeElement) {
PDFStructElem parent = (structureTreeElement instanceof PDFStructElem.Placeholder)
? structureTreeElement.getParentStructElem()
: structureTreeElement;
pageParentTreeArray.add(parent);
String type = parent.getStructureType().toString();
int mcid = pageParentTreeArray.length() - 1;
return new MarkedContentInfo(type, mcid, structureTreeElement);
}

/**
* Adds a content item corresponding to text into the structure tree, if
* there is a structure element associated to it.
*
* @param structurePointer reference to the parent structure element of the
* piece of text
* @param structElem the parent structure element of the piece of text
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that content, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The content
* must then be treated as an artifact.
*/
MarkedContentInfo addTextContentItem(String structurePointer) {
MarkedContentInfo mci = addToParentTree(structurePointer);
if (mci != ARTIFACT) {
MarkedContentInfo addTextContentItem(PDFStructElem structElem) {
if (structElem == null) {
return ARTIFACT;
} else {
MarkedContentInfo mci = addToParentTree(structElem);
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", MCR);
contentItem.put("Pg", this.currentPage);
contentItem.put("MCID", mci.mcid);
mci.parent.addKid(contentItem);
return mci;
}
return mci;
}

/**
* Adds a content item corresponding to an image into the structure tree, if
* there is a structure element associated to it.
*
* @param structurePointer reference to the parent structure element of the
* image
* @param structElem the parent structure element of the image
* @return the necessary information for bracketing the content as a
* marked-content sequence. If there is no element in the structure tree
* associated to that image, returns an instance whose
* {@link MarkedContentInfo#tag} value is <code>null</code>. The image
* must then be treated as an artifact.
* {@link MarkedContentInfo#tag} value is <code>null</code>. The image must
* then be treated as an artifact.
*/
MarkedContentInfo addImageContentItem(String structurePointer) {
MarkedContentInfo mci = addToParentTree(structurePointer);
if (mci != ARTIFACT) {
MarkedContentInfo addImageContentItem(PDFStructElem structElem) {
if (structElem == null) {
return ARTIFACT;
} else {
MarkedContentInfo mci = addToParentTree(structElem);
mci.parent.setMCIDKid(mci.mcid);
mci.parent.setPage(this.currentPage);
return mci;
}
return mci;
}

// While the PDF spec allows images to be referred as PDF objects, this
// makes the Acrobat Pro checker complain that the image is not accessible.
// Its alt-text is still read aloud though. Using marked-content sequences
// like for text works.
// MarkedContentInfo addImageObject(String parentReference) {
// MarkedContentInfo mci = addToParentTree(parentReference);
// if (mci != ARTIFACT) {
// PDFDictionary contentItem = new PDFDictionary();
// contentItem.put("Type", OBJR);
// contentItem.put("Pg", this.currentPage);
// contentItem.put("Obj", null);
// mci.parent.addKid(contentItem);
// }
// return mci;
// }

/**
* Adds a content item corresponding to the given link into the structure
* tree.
*
* @param link a link
* @param structurePointer reference to the corresponding parent structure element
* @param structureTreeElement its parent structure element
*/
void addLinkContentItem(PDFLink link, String structurePointer) {
void addLinkContentItem(PDFLink link, PDFStructElem structureTreeElement) {
int structParent = getNextParentTreeKey();
link.setStructParent(structParent);
PDFDictionary contentItem = new PDFDictionary();
contentItem.put("Type", OBJR);
contentItem.put("Pg", this.currentPage);
contentItem.put("Obj", link);
PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
parentTree.getNums().put(structParent, parent);
parent.addKid(contentItem);
}

void addStructurePointer(String ptr, PDFStructElem structElem) {
structTreeMap.put(ptr, structElem);
parentTree.getNums().put(structParent, structureTreeElement);
structureTreeElement.addKid(contentItem);
}

}

+ 11
- 10
src/java/org/apache/fop/render/pdf/PDFPainter.java View File

@@ -37,6 +37,7 @@ import org.apache.fop.fonts.SingleByteFont;
import org.apache.fop.fonts.Typeface;
import org.apache.fop.pdf.PDFDocument;
import org.apache.fop.pdf.PDFNumber;
import org.apache.fop.pdf.PDFStructElem;
import org.apache.fop.pdf.PDFTextUtil;
import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.RenderingContext;
@@ -133,24 +134,24 @@ public class PDFPainter extends AbstractIFPainter {
PDFXObject xobject = getPDFDoc().getXObject(uri);
if (xobject != null) {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
prepareImageMCID(structElem);
placeImageAccess(rect, xobject);
} else {
placeImage(rect, xobject);
}
} else {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
prepareImageMCID(structElem);
}
drawImageUsingURI(uri, rect);
flushPDFDoc();
}
}

private void prepareImageMCID(String ptr) {
imageMCI = logicalStructureHandler.addImageContentItem(ptr);
private void prepareImageMCID(PDFStructElem structElem) {
imageMCI = logicalStructureHandler.addImageContentItem(structElem);
}

/** {@inheritDoc} */
@@ -194,8 +195,8 @@ public class PDFPainter extends AbstractIFPainter {
/** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect) throws IFException {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
prepareImageMCID(ptr);
PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
prepareImageMCID(structElem);
}
drawImageUsingDocument(doc, rect);
flushPDFDoc();
@@ -294,8 +295,8 @@ public class PDFPainter extends AbstractIFPainter {
String text)
throws IFException {
if (accessEnabled) {
String ptr = getContext().getStructurePointer();
MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr);
PDFStructElem structElem = (PDFStructElem) getContext().getStructureTreeElement();
MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(structElem);
if (generator.getTextUtil().isInTextObject()) {
generator.separateTextElements(mci.tag, mci.mcid);
}

+ 51
- 20
src/java/org/apache/fop/render/pdf/PDFStructureTreeBuilder.java View File

@@ -24,10 +24,10 @@ import java.util.Locale;

import org.xml.sax.Attributes;

import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fo.extensions.ExtensionElementMapping;
import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.pdf.PDFFactory;
import org.apache.fop.pdf.PDFStructElem;

@@ -61,33 +61,64 @@ class PDFStructureTreeBuilder implements StructureTreeEventHandler {
public void endPageSequence() {
}

public void startNode(String name, Attributes attributes) {
public StructureTreeElement startNode(String name, Attributes attributes) {
PDFStructElem parent = ancestors.getFirst();
String role = attributes.getValue("role");
PDFStructElem created = pdfFactory.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent,
eventBroadcaster), parent);
if (ancestors.size() <= 2) { // TODO remove
parent.addKid(created);
}
String ptr = attributes.getValue(InternalElementMapping.URI, "ptr");
if (ptr != null) {
logicalStructureHandler.addStructurePointer(ptr, created);
PDFStructElem created;
created = pdfFactory.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent);
parent.addKid(created);
ancestors.addFirst(created);
return created;
}

public void endNode(String name) {
removeFirstAncestor();
}

private void removeFirstAncestor() {
ancestors.removeFirst();
}

public StructureTreeElement startImageNode(String name, Attributes attributes) {
PDFStructElem parent = ancestors.getFirst();
String role = attributes.getValue("role");
PDFStructElem created;
created = pdfFactory.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent, eventBroadcaster), parent);
parent.addKid(created);
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
if (altTextNode != null) {
created.put("Alt", altTextNode);
} else {
created.put("Alt", "No alternate text specified");
}
ancestors.addFirst(created);
return created;
}

public void endImageNode(String name) {
removeFirstAncestor();
}

if (name.equals("external-graphic") || name.equals("instream-foreign-object")) {
String altTextNode = attributes.getValue(ExtensionElementMapping.URI, "alt-text");
if (altTextNode != null) {
created.put("Alt", altTextNode);
} else {
created.put("Alt", "No alternate text specified");
}
public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
PDFStructElem parent = ancestors.getFirst();
String role = attributes.getValue("role");
PDFStructElem created;
if ("#PCDATA".equals(name)) {
created = new PDFStructElem.Placeholder(parent, name);
} else {
created = pdfFactory.makeStructureElement(
FOToPDFRoleMap.mapFormattingObject(name, role, parent,
eventBroadcaster), parent);
}
parent.addKid(created);
ancestors.addFirst(created);
return created;
}

public void endNode(String name) {
ancestors.removeFirst();
public void endReferencedNode(String name) {
removeFirstAncestor();
}

}

+ 5
- 7
src/java/org/apache/fop/render/rtf/RTFHandler.java View File

@@ -117,13 +117,13 @@ import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfFootnote;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfHyperLink;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfList;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfPage;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfSection;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTable;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableCell;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTableRow;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfTextrun;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfListItem.RtfListItemLabel;
import org.apache.fop.render.rtf.rtflib.tools.BuilderContext;
import org.apache.fop.render.rtf.rtflib.tools.PercentContext;
import org.apache.fop.render.rtf.rtflib.tools.TableContext;
@@ -1362,11 +1362,9 @@ public class RTFHandler extends FOEventHandler {

/**
* @param text FOText object
* @param data Array of characters to process.
* @param start Offset for characters to process.
* @param length Portion of array to process.
* @param characters CharSequence of the characters to process.
*/
public void text(FOText text, char[] data, int start, int length) {
public void text(FOText text, CharSequence characters) {
if (bDefer) {
return;
}
@@ -1381,7 +1379,7 @@ public class RTFHandler extends FOEventHandler {
= TextAttributesConverter.convertCharacterAttributes(text);

textrun.pushInlineAttributes(rtfAttr);
textrun.addString(new String(data, start, length - start));
textrun.addString(characters.toString());
textrun.popInlineAttributes();
} catch (IOException ioe) {
handleIOTrouble(ioe);
@@ -1558,7 +1556,7 @@ public class RTFHandler extends FOEventHandler {
} else if (foNode instanceof FOText) {
if (bStart) {
FOText text = (FOText) foNode;
text(text, text.getCharArray(), 0, text.length());
text(text, text.getCharSequence());
}
} else if (foNode instanceof Character) {
if (bStart) {

+ 2
- 2
test/accessibility/background-image_jpg_repeat.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/bgimg72dpi.jpg"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/background-image_jpg_single.fo View File

@@ -16,7 +16,7 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
@@ -25,7 +25,7 @@
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/background-image_png_repeat.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/bgimg72dpi.png"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/background-image_png_single.fo View File

@@ -16,7 +16,7 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
@@ -25,7 +25,7 @@
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/background-image_svg_repeat.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body background-image="../resources/images/rgb-circles.svg"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/background-image_svg_single.fo View File

@@ -16,7 +16,7 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
@@ -25,7 +25,7 @@
background-position-vertical="50%"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 3
- 3
test/accessibility/complete.fo View File

@@ -17,7 +17,7 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
@@ -25,7 +25,7 @@
<fo:region-before extent="12pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="8pt" text-align-last="justify">This is the page header<fo:leader/>Page
<fo:page-number/></fo:block>
@@ -117,7 +117,7 @@
<fo:block>And now we are going to see how a second page sequence is handled.</fo:block>
</fo:flow>
</fo:page-sequence>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="8pt" text-align-last="justify">This is the page header<fo:leader/>Page
<fo:page-number/></fo:block>

+ 2
- 2
test/accessibility/image_jpg.fo View File

@@ -17,14 +17,14 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the JPEG format: <fo:external-graphic
src="../resources/images/cmyk.jpg"

+ 2
- 2
test/accessibility/image_png.fo View File

@@ -17,14 +17,14 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the PNG format: <fo:external-graphic
src="../resources/images/fop-logo-color-24bit.png"

+ 2
- 2
test/accessibility/image_svg.fo View File

@@ -17,14 +17,14 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the SVG format: <fo:external-graphic
src="../resources/images/circles.svg"

+ 2
- 2
test/accessibility/image_wmf.fo View File

@@ -17,14 +17,14 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="320pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This document contains an image in the WMF format: <fo:external-graphic
src="../resources/images/testChart.wmf"

+ 2
- 2
test/accessibility/leader.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify"
text-align-last="justify">
<fo:block>This is a text followed by a leader with leader-pattern=​"use-content", the

+ 2
- 2
test/accessibility/links.fo View File

@@ -17,14 +17,14 @@
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>This is a <fo:wrapper color="blue"><fo:basic-link
internal-destination="FOP">link</fo:basic-link></fo:wrapper> to the next

BIN
test/accessibility/pdf/background-image_jpg_repeat.pdf View File


BIN
test/accessibility/pdf/background-image_jpg_single.pdf View File


BIN
test/accessibility/pdf/background-image_png_repeat.pdf View File


BIN
test/accessibility/pdf/background-image_png_single.pdf View File


BIN
test/accessibility/pdf/background-image_svg_repeat.pdf View File


BIN
test/accessibility/pdf/background-image_svg_single.pdf View File


BIN
test/accessibility/pdf/complete.pdf View File


BIN
test/accessibility/pdf/image_jpg.pdf View File


BIN
test/accessibility/pdf/image_png.pdf View File


BIN
test/accessibility/pdf/image_svg.pdf View File


BIN
test/accessibility/pdf/image_wmf.pdf View File


BIN
test/accessibility/pdf/leader.pdf View File


BIN
test/accessibility/pdf/links.pdf View File


BIN
test/accessibility/pdf/role.pdf View File


BIN
test/accessibility/pdf/role_non-standard.pdf View File


BIN
test/accessibility/pdf/text_1.pdf View File


BIN
test/accessibility/pdf/text_2.pdf View File


BIN
test/accessibility/pdf/text_font-embedding.pdf View File


+ 2
- 2
test/accessibility/role.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" font-family="sans-serif">
<fo:block role="H1" font-weight="bold" font-size="150%"
space-before.minimum="1.5em"

+ 2
- 2
test/accessibility/role_non-standard.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" font-family="sans-serif">
<fo:block role="H1" font-weight="bold" font-size="150%"
space-before.minimum="1.5em"

+ 2
- 2
test/accessibility/text_1.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/text_2.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 2
- 2
test/accessibility/text_font-embedding.fo View File

@@ -16,14 +16,14 @@
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" language="en" country="GB">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="220pt" page-width="320pt" margin="10pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" language="en" country="GB">
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" hyphenate="true" text-align="justify" font-family="DejaVu">
<fo:block>Apache FOP (Formatting Objects Processor) is a print formatter driven by XSL
formatting objects (XSL-FO) and an output independent formatter. It is a Java application

+ 54
- 0
test/java/org/apache/fop/accessibility/fo/DOMResultUtil.java View File

@@ -0,0 +1,54 @@
/*
* 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.accessibility.fo;

import java.io.File;

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.stream.StreamResult;

/**
* Utility class to stream an instance of {@link DOMResult} into a file. May be
* useful for debugging.
*/
final class DOMResultUtil {

private DOMResultUtil() {
}

/**
* Streams the given result into a file of the given name.
*
* @param result the result of a transformation
* @param filename name of the file into which to stream the result
* @throws TransformerException if a problem occurs when streaming
*/
public static void streamToFile(DOMResult result, String filename) throws TransformerException {
DOMSource source = new DOMSource(result.getNode());
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.transform(source, new StreamResult(new File(filename)));
}

}

test/java/org/apache/fop/accessibility/FO2StructureTreeConverterTestCase.java → test/java/org/apache/fop/accessibility/fo/FO2StructureTreeConverterTestCase.java View File

@@ -17,10 +17,12 @@

/* $Id$ */

package org.apache.fop.accessibility;
package org.apache.fop.accessibility.fo;

import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

@@ -34,18 +36,17 @@ import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.DifferenceConstants;
import org.custommonkey.xmlunit.DifferenceListener;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.fop.accessibility.StructureTree2SAXEventAdapter;
import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.FODocumentParser;
@@ -56,54 +57,75 @@ import org.apache.fop.fotreetest.DummyFOEventHandler;

public class FO2StructureTreeConverterTestCase {

private static class IgnoringPtrDifferenceListener implements DifferenceListener {

public int differenceFound(Difference difference) {
switch (difference.getId()) {
case DifferenceConstants.ELEMENT_NUM_ATTRIBUTES_ID:
return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
case DifferenceConstants.ATTR_NAME_NOT_FOUND_ID:
String additionalAttribute = difference.getTestNodeDetail().getValue();
if (additionalAttribute.equals("ptr")) {
return RETURN_IGNORE_DIFFERENCE_NODES_SIMILAR;
} else {
return RETURN_ACCEPT_DIFFERENCE;
}
default:
return RETURN_ACCEPT_DIFFERENCE;
}
}
private interface FOLoader {

public void skippedComparison(Node control, Node test) {
throw new UnsupportedOperationException("Not implemented");
}
InputStream getFoInputStream();
}

private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence";

private FOLoader foLoader;

@Test
public void testCompleteDocument() throws Exception {
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return getResource("/org/apache/fop/fo/complete_document.fo");
}
};
testConverter();
}

@Test
public void testTableFooters() throws Exception {
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return getResource("table-footers.fo");
}
};
testConverter();
}

@Test
public void testConverter() throws Exception {
public void testCompleteContentWrappedInTableFooter() throws Exception {
Source xslt = new StreamSource(getResource("wrapCompleteDocumentInTableFooter.xsl"));
Transformer transformer = createTransformer(xslt);
InputStream originalFO = getResource("/org/apache/fop/fo/complete_document.fo");
ByteArrayOutputStream transformedFoOutput = new ByteArrayOutputStream();
transformer.transform(new StreamSource(originalFO), new StreamResult(transformedFoOutput));
final byte[] transformedFoOutputBytes = transformedFoOutput.toByteArray();
foLoader = new FOLoader() {
public InputStream getFoInputStream() {
return new ByteArrayInputStream(transformedFoOutputBytes);
}
};
testConverter();
}

private Transformer createTransformer(Source xslt) throws TransformerFactoryConfigurationError,
TransformerConfigurationException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
return transformerFactory.newTransformer(xslt);
}

private static InputStream getResource(String name) {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(name);
}

private void testConverter() throws Exception {
DOMResult expectedStructureTree = loadExpectedStructureTree();
DOMResult actualStructureTree = buildActualStructureTree();
final Diff diff = createDiff(expectedStructureTree, actualStructureTree);
assertTrue(diff.toString(), diff.similar());
assertTrue(diff.toString(), diff.identical());
}

private static DOMResult loadExpectedStructureTree() {
private DOMResult loadExpectedStructureTree() {
DOMResult expectedStructureTree = new DOMResult();
runXSLT(getXsltInputStream(), getFoInputStream(), expectedStructureTree);
InputStream xslt = getResource("fo2StructureTree.xsl");
runXSLT(xslt, foLoader.getFoInputStream(), expectedStructureTree);
return expectedStructureTree;
}

private static InputStream getXsltInputStream() {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream("foToIfStructureTree.xsl");
}

private static InputStream getFoInputStream() {
return FO2StructureTreeConverterTestCase.class.getResourceAsStream(
"/org/apache/fop/fo/complete_document.fo");
}

private static void runXSLT(InputStream xslt, InputStream doc, Result result) {
Source fo = new StreamSource(doc);
try {
@@ -128,15 +150,15 @@ public class FO2StructureTreeConverterTestCase {
}
}

private static DOMResult buildActualStructureTree() throws Exception {
private DOMResult buildActualStructureTree() throws Exception {
DOMResult actualStructureTree = new DOMResult();
createStructureTreeFromDocument(getFoInputStream(), actualStructureTree);
createStructureTreeFromDocument(foLoader.getFoInputStream(), actualStructureTree);
return actualStructureTree;
}

private static void createStructureTreeFromDocument(InputStream foInputStream,
DOMResult domResult) throws Exception {
TransformerHandler tHandler = createTransformerHandler(domResult);
Result result) throws Exception {
TransformerHandler tHandler = createTransformerHandler(result);
startStructureTreeSequence(tHandler);
StructureTreeEventHandler structureTreeEventHandler
= StructureTree2SAXEventAdapter.newInstance(tHandler);
@@ -146,7 +168,7 @@ public class FO2StructureTreeConverterTestCase {
endStructureTreeSequence(tHandler);
}

private static TransformerHandler createTransformerHandler(DOMResult domResult)
private static TransformerHandler createTransformerHandler(Result domResult)
throws TransformerConfigurationException, TransformerFactoryConfigurationError {
SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
TransformerHandler transformerHandler = factory.newTransformerHandler();
@@ -192,7 +214,6 @@ public class FO2StructureTreeConverterTestCase {

private static Diff createDiff(DOMResult expected, DOMResult actual) {
Diff diff = new Diff(getDocument(expected), getDocument(actual));
diff.overrideDifferenceListener(new IgnoringPtrDifferenceListener());
return diff;
}


test/java/org/apache/fop/accessibility/fo2StructureTree.xsl → test/java/org/apache/fop/accessibility/fo/fo2StructureTree.xsl View File

@@ -69,10 +69,18 @@
</xsl:template>

<!-- Formatting Objects for Tables -->
<xsl:template match="fo:table-and-caption|fo:table-caption|fo:table">
<xsl:template match="fo:table-and-caption|fo:table-caption">
<xsl:call-template name="copy"/>
</xsl:template>

<xsl:template match="fo:table">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*[name() != 'fo:table-footer']"/>
<xsl:apply-templates select="fo:table-footer"/>
</xsl:copy>
</xsl:template>

<xsl:template match="fo:table-header|fo:table-footer|fo:table-body|fo:table-row|fo:table-cell">
<xsl:call-template name="copy"/>
</xsl:template>
@@ -110,7 +118,18 @@
<xsl:template match="@*"/>


<!-- Discard text -->
<!-- Discard text nodes... -->
<xsl:template match="text()"/>

<!-- ...except those that will result into marked content -->
<xsl:template match="fo:title/text()
|fo:block/text()
|fo:bidi-override/text()
|fo:inline/text()
|fo:basic-link/text()
|fo:wrapper/text()
|fo:marker/text()">
<marked-content xmlns="http://xmlgraphics.apache.org/fop/intermediate"/>
</xsl:template>

</xsl:stylesheet>

+ 195
- 0
test/java/org/apache/fop/accessibility/fo/table-footers.fo View File

@@ -0,0 +1,195 @@
<?xml version="1.0" standalone="no"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="440pt" page-width="420pt" margin="10pt">
<fo:region-body display-align="center"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page">
<fo:flow flow-name="xsl-region-body" line-height="10pt" font-size="8pt">
<fo:table width="100% - 6pt" table-layout="fixed"
border-collapse="separate" border="2pt solid black" border-separation="2pt" padding="1pt"
start-indent="3pt" end-indent="3pt" space-after="2pt">
<fo:table-header start-indent="0" end-indent="0">
<fo:table-cell background-color="#E0E0E0" padding="2pt">
<fo:block>Start Outer Header</fo:block>
<fo:table width="100% - 6pt" table-layout="fixed"
border="2pt solid red" padding="1pt"
start-indent="3pt" end-indent="3pt" space-after="2pt">
<fo:table-header start-indent="0" end-indent="0">
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Header 1.2</fo:block>
</fo:table-cell>
</fo:table-header>
<fo:table-footer start-indent="0" end-indent="0">
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Footer 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Footer 1.2</fo:block>
</fo:table-cell>
</fo:table-footer>
<fo:table-body start-indent="0" end-indent="0">
<fo:table-row>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Body 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Body 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Body 2.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="#FFB0B0" padding="2pt">
<fo:block>Inner Body 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>End Outer Header</fo:block>
</fo:table-cell>
</fo:table-header>
<fo:table-footer start-indent="0" end-indent="0">
<fo:table-cell background-color="#E0E0E0" padding="2pt">
<fo:block>Start Outer Footer</fo:block>
<fo:table width="100% - 6pt" table-layout="fixed"
border="2pt solid green" padding="1pt"
start-indent="3pt" end-indent="3pt" space-after="2pt">
<fo:table-header start-indent="0" end-indent="0">
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Header 1.2</fo:block>
</fo:table-cell>
</fo:table-header>
<fo:table-footer start-indent="0" end-indent="0">
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Start Inner Footer 1.1</fo:block>
<fo:table width="100% - 6pt" table-layout="fixed"
border="2pt solid yellow" padding="1pt"
start-indent="3pt" end-indent="3pt" space-after="2pt">
<fo:table-header start-indent="0" end-indent="0">
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Header 1.2</fo:block>
</fo:table-cell>
</fo:table-header>
<fo:table-footer start-indent="0" end-indent="0">
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Footer 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Footer 1.2</fo:block>
</fo:table-cell>
</fo:table-footer>
<fo:table-body start-indent="0" end-indent="0">
<fo:table-row>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Body 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Body 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Body 2.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="yellow" padding="2pt">
<fo:block>Inner Inner Body 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>End Inner Footer 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Footer 1.2</fo:block>
</fo:table-cell>
</fo:table-footer>
<fo:table-body start-indent="0" end-indent="0">
<fo:table-row>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Body 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Body 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Body 2.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightgreen" padding="2pt">
<fo:block>Inner Body 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>End Outer Footer</fo:block>
</fo:table-cell>
</fo:table-footer>
<fo:table-body start-indent="0" end-indent="0">
<fo:table-row>
<fo:table-cell background-color="#E0E0E0" padding="2pt">
<fo:block>Outer Body Cell 1</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="#E0E0E0" padding="2pt">
<fo:block>Start Outer Body Cell 2</fo:block>
<fo:table width="100% - 6pt" table-layout="fixed"
border="2pt solid blue" padding="1pt"
start-indent="3pt" end-indent="3pt" space-after="2pt">
<fo:table-header start-indent="0" end-indent="0">
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Footer 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Footer 1.2</fo:block>
</fo:table-cell>
</fo:table-header>
<fo:table-footer start-indent="0" end-indent="0">
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Header 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Header 1.2</fo:block>
</fo:table-cell>
</fo:table-footer>
<fo:table-body start-indent="0" end-indent="0">
<fo:table-row>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Body 1.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Body 1.2</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Body 2.1</fo:block>
</fo:table-cell>
<fo:table-cell background-color="lightblue" padding="2pt">
<fo:block>Inner Body 2.2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
<fo:block>End Outer Body Cell 2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>

+ 66
- 0
test/java/org/apache/fop/accessibility/fo/wrapCompleteDocumentInTableFooter.xsl View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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$ -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">

<xsl:template match="@*|node()" name="copy">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>


<xsl:template match="/">
<fo:root>
<fo:layout-master-set>
<fo:simple-page-master master-name="page"
page-height="500pt" page-width="300pt" margin="20pt">
<fo:region-body margin-top="20pt"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:apply-templates select="//fo:page-sequence"/>
</fo:root>
</xsl:template>

<xsl:template match="fo:page-sequence">
<fo:page-sequence master-reference="page">
<xsl:apply-templates select="fo:flow"/>
</fo:page-sequence>
</xsl:template>

<xsl:template match="fo:flow">
<xsl:copy>
<xsl:apply-templates select="@*[not(starts-with(name(), 'space-before'))]"/>
<fo:table width="100%" table-layout="fixed">
<fo:table-footer>
<fo:table-cell background-color="#F0F0F0">
<xsl:apply-templates select="@*[starts-with(name(), 'space-before')]"/>
<xsl:apply-templates select="*"/>
</fo:table-cell>
</fo:table-footer>
<fo:table-body>
<fo:table-cell>
<fo:block>The content below is in the table footer.</fo:block>
</fo:table-cell>
</fo:table-body>
</fo:table>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

+ 1
- 1
test/java/org/apache/fop/render/intermediate/IFStructureTreeBuilderTestCase.java View File

@@ -85,7 +85,7 @@ public class IFStructureTreeBuilderTestCase {

@Test
public void startNode() throws Exception {
final String[] attributes = {"ptr", "1"};
final String[] attributes = {"struct-id", "1"};
final String nodeName = "block";
final ContentHandler handler = mock(ContentHandler.class);


Loading…
Cancel
Save