* 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-ffa450edef68tags/fop-1_1rc1old
@@ -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"/> |
@@ -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) { | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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 { | |||
} |
@@ -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. | |||
*/ |
@@ -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 |
@@ -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); | |||
} | |||
}); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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) { |
@@ -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)); |
@@ -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 |
@@ -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) { | |||
} | |||
/** |
@@ -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(); | |||
} | |||
@@ -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; | |||
} | |||
} |
@@ -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; |
@@ -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); | |||
} | |||
/** |
@@ -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() { |
@@ -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 */ |
@@ -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; | |||
} | |||
/** |
@@ -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; |
@@ -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} */ |
@@ -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"; |
@@ -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} */ |
@@ -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. |
@@ -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(); | |||
} |
@@ -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(); |
@@ -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); | |||
} | |||
} | |||
@@ -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); |
@@ -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()); | |||
} | |||
@@ -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(); |
@@ -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; | |||
} | |||
@@ -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; |
@@ -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); | |||
} |
@@ -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)); | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
/** |
@@ -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) { |
@@ -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); |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
/** |
@@ -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 { |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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) { |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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> |
@@ -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" |
@@ -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" |
@@ -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" |
@@ -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" |
@@ -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 |
@@ -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 |
@@ -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" |
@@ -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" |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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))); | |||
} | |||
} |
@@ -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; | |||
} | |||
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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); | |||