</xs:element>
<xs:element name="header">
<xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <!--xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/-->
- <xs:any namespace="##other" processContents="lax"/>
- </xs:choice>
+ <xs:sequence>
+ <xs:element name="locale" minOccurs="0" maxOccurs="1">
+ <xs:complexType>
+ <xs:attributeGroup ref="mf:foreignAtts"/>
+ </xs:complexType>
+ </xs:element>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <!--xs:element ref="x:xmpmeta" xmlns:x="adobe:ns:meta/"/-->
+ <xs:any namespace="##other" processContents="lax"/>
+ </xs:choice>
+ </xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="trailer">
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+import java.util.Locale;
+
+import org.xml.sax.Attributes;
+
+/**
+ * This implementation ignores all structure tree events.
+ */
+public final class DummyStructureTreeEventHandler implements StructureTreeEventHandler {
+
+ /** The singleton instance of this class. */
+ public static final StructureTreeEventHandler INSTANCE = new DummyStructureTreeEventHandler();
+
+ private DummyStructureTreeEventHandler() { }
+
+ /** {@inheritDoc} */
+ public void startPageSequence(Locale locale) {
+ }
+
+ /** {@inheritDoc} */
+ public void startNode(String name, Attributes attributes) {
+ }
+
+ /** {@inheritDoc} */
+ public void endNode(String name) {
+ }
+
+ /** {@inheritDoc} */
+ public void endPageSequence() {
+ }
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+import java.util.Locale;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.apps.FOUserAgent;
+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.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;
+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;
+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
+ * events into appropriate structure tree events.
+ */
+public class FO2StructureTreeConverter extends DelegatingFOEventHandler {
+
+ private int idCounter;
+
+ /** Delegates to either {@link #foToStructureTreeEventAdapter} or {@link #eventSwallower}. */
+ 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);
+ }
+
+ @Override
+ public void startBlockContainer(BlockContainer blc) {
+ startElement(blc);
+ }
+
+ @Override
+ public void endBlockContainer(BlockContainer blc) {
+ endElement(blc);
+ }
+
+ @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);
+ }
+
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param structureTreeEventHandler the object that will hold the structure tree
+ * @param delegate the FO event handler that must be wrapped by this instance
+ */
+ public FO2StructureTreeConverter(StructureTreeEventHandler structureTreeEventHandler,
+ FOEventHandler delegate) {
+ super(delegate);
+ this.structureTreeEventHandler = structureTreeEventHandler;
+ this.foToStructureTreeEventAdapter = new FOToStructureTreeEventAdapter(foUserAgent);
+ this.converter = foToStructureTreeEventAdapter;
+ this.eventSwallower = new FOEventHandler(foUserAgent) { };
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+ converter.startDocument();
+ super.startDocument();
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ converter.endDocument();
+ super.endDocument();
+ }
+
+ @Override
+ public void startRoot(Root root) {
+ converter.startRoot(root);
+ super.startRoot(root);
+ }
+
+ @Override
+ public void endRoot(Root root) {
+ converter.endRoot(root);
+ super.endRoot(root);
+ }
+
+ @Override
+ public void startPageSequence(PageSequence pageSeq) {
+ converter.startPageSequence(pageSeq);
+ super.startPageSequence(pageSeq);
+ }
+
+ @Override
+ public void endPageSequence(PageSequence pageSeq) {
+ converter.endPageSequence(pageSeq);
+ super.endPageSequence(pageSeq);
+ }
+
+ @Override
+ public void startPageNumber(PageNumber pagenum) {
+ converter.startPageNumber(pagenum);
+ super.startPageNumber(pagenum);
+ }
+
+ @Override
+ public void endPageNumber(PageNumber pagenum) {
+ converter.endPageNumber(pagenum);
+ super.endPageNumber(pagenum);
+ }
+
+ @Override
+ public void startPageNumberCitation(PageNumberCitation pageCite) {
+ converter.startPageNumberCitation(pageCite);
+ super.startPageNumberCitation(pageCite);
+ }
+
+ @Override
+ public void endPageNumberCitation(PageNumberCitation pageCite) {
+ converter.endPageNumberCitation(pageCite);
+ super.endPageNumberCitation(pageCite);
+ }
+
+ @Override
+ public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
+ converter.startPageNumberCitationLast(pageLast);
+ super.startPageNumberCitationLast(pageLast);
+ }
+
+ @Override
+ public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
+ converter.endPageNumberCitationLast(pageLast);
+ super.endPageNumberCitationLast(pageLast);
+ }
+
+ @Override
+ public void startFlow(Flow fl) {
+ converter.startFlow(fl);
+ super.startFlow(fl);
+ }
+
+ @Override
+ public void endFlow(Flow fl) {
+ converter.endFlow(fl);
+ super.endFlow(fl);
+ }
+
+ @Override
+ public void startBlock(Block bl) {
+ converter.startBlock(bl);
+ super.startBlock(bl);
+ }
+
+ @Override
+ public void endBlock(Block bl) {
+ converter.endBlock(bl);
+ super.endBlock(bl);
+ }
+
+ @Override
+ public void startBlockContainer(BlockContainer blc) {
+ converter.startBlockContainer(blc);
+ super.startBlockContainer(blc);
+ }
+
+ @Override
+ public void endBlockContainer(BlockContainer blc) {
+ converter.endBlockContainer(blc);
+ super.endBlockContainer(blc);
+ }
+
+ @Override
+ public void startInline(Inline inl) {
+ converter.startInline(inl);
+ super.startInline(inl);
+ }
+
+ @Override
+ public void endInline(Inline inl) {
+ converter.endInline(inl);
+ super.endInline(inl);
+ }
+
+ @Override
+ public void startTable(Table tbl) {
+ converter.startTable(tbl);
+ super.startTable(tbl);
+ }
+
+ @Override
+ public void endTable(Table tbl) {
+ converter.endTable(tbl);
+ super.endTable(tbl);
+ }
+
+ @Override
+ public void startColumn(TableColumn tc) {
+ converter.startColumn(tc);
+ super.startColumn(tc);
+ }
+
+ @Override
+ public void endColumn(TableColumn tc) {
+ converter.endColumn(tc);
+ super.endColumn(tc);
+ }
+
+ @Override
+ public void startHeader(TableHeader header) {
+ converter.startHeader(header);
+ super.startHeader(header);
+ }
+
+ @Override
+ public void endHeader(TableHeader header) {
+ converter.endHeader(header);
+ super.endHeader(header);
+ }
+
+ @Override
+ public void startFooter(TableFooter footer) {
+ converter.startFooter(footer);
+ super.startFooter(footer);
+ }
+
+ @Override
+ public void endFooter(TableFooter footer) {
+ converter.endFooter(footer);
+ super.endFooter(footer);
+ }
+
+ @Override
+ public void startBody(TableBody body) {
+ converter.startBody(body);
+ super.startBody(body);
+ }
+
+ @Override
+ public void endBody(TableBody body) {
+ converter.endBody(body);
+ super.endBody(body);
+ }
+
+ @Override
+ public void startRow(TableRow tr) {
+ converter.startRow(tr);
+ super.startRow(tr);
+ }
+
+ @Override
+ public void endRow(TableRow tr) {
+ converter.endRow(tr);
+ super.endRow(tr);
+ }
+
+ @Override
+ public void startCell(TableCell tc) {
+ converter.startCell(tc);
+ super.startCell(tc);
+ }
+
+ @Override
+ public void endCell(TableCell tc) {
+ converter.endCell(tc);
+ super.endCell(tc);
+ }
+
+ @Override
+ public void startList(ListBlock lb) {
+ converter.startList(lb);
+ super.startList(lb);
+ }
+
+ @Override
+ public void endList(ListBlock lb) {
+ converter.endList(lb);
+ super.endList(lb);
+ }
+
+ @Override
+ public void startListItem(ListItem li) {
+ converter.startListItem(li);
+ super.startListItem(li);
+ }
+
+ @Override
+ public void endListItem(ListItem li) {
+ converter.endListItem(li);
+ super.endListItem(li);
+ }
+
+ @Override
+ public void startListLabel(ListItemLabel listItemLabel) {
+ converter.startListLabel(listItemLabel);
+ super.startListLabel(listItemLabel);
+ }
+
+ @Override
+ public void endListLabel(ListItemLabel listItemLabel) {
+ converter.endListLabel(listItemLabel);
+ super.endListLabel(listItemLabel);
+ }
+
+ @Override
+ public void startListBody(ListItemBody listItemBody) {
+ converter.startListBody(listItemBody);
+ super.startListBody(listItemBody);
+ }
+
+ @Override
+ public void endListBody(ListItemBody listItemBody) {
+ converter.endListBody(listItemBody);
+ super.endListBody(listItemBody);
+ }
+
+ @Override
+ public void startStatic(StaticContent staticContent) {
+ converter.startStatic(staticContent);
+ super.startStatic(staticContent);
+ }
+
+ @Override
+ public void endStatic(StaticContent statisContent) {
+ converter.endStatic(statisContent);
+ super.endStatic(statisContent);
+ }
+
+ @Override
+ public void startMarkup() {
+ converter.startMarkup();
+ super.startMarkup();
+ }
+
+ @Override
+ public void endMarkup() {
+ converter.endMarkup();
+ super.endMarkup();
+ }
+
+ @Override
+ public void startLink(BasicLink basicLink) {
+ converter.startLink(basicLink);
+ super.startLink(basicLink);
+ }
+
+ @Override
+ public void endLink(BasicLink basicLink) {
+ converter.endLink(basicLink);
+ super.endLink(basicLink);
+ }
+
+ @Override
+ public void image(ExternalGraphic eg) {
+ converter.image(eg);
+ super.image(eg);
+ }
+
+ @Override
+ public void pageRef() {
+ converter.pageRef();
+ super.pageRef();
+ }
+
+ @Override
+ public void startInstreamForeignObject(InstreamForeignObject ifo) {
+ converter.startInstreamForeignObject(ifo);
+ super.startInstreamForeignObject(ifo);
+ }
+
+ @Override
+ public void endInstreamForeignObject(InstreamForeignObject ifo) {
+ converter.endInstreamForeignObject(ifo);
+ super.endInstreamForeignObject(ifo);
+ }
+
+ @Override
+ public void startFootnote(Footnote footnote) {
+ converter.startFootnote(footnote);
+ super.startFootnote(footnote);
+ }
+
+ @Override
+ public void endFootnote(Footnote footnote) {
+ converter.endFootnote(footnote);
+ super.endFootnote(footnote);
+ }
+
+ @Override
+ public void startFootnoteBody(FootnoteBody body) {
+ converter.startFootnoteBody(body);
+ super.startFootnoteBody(body);
+ }
+
+ @Override
+ public void endFootnoteBody(FootnoteBody body) {
+ converter.endFootnoteBody(body);
+ super.endFootnoteBody(body);
+ }
+
+ @Override
+ public void startLeader(Leader l) {
+ converter = eventSwallower;
+ converter.startLeader(l);
+ super.startLeader(l);
+ }
+
+ @Override
+ public void endLeader(Leader l) {
+ converter.endLeader(l);
+ converter = foToStructureTreeEventAdapter;
+ super.endLeader(l);
+ }
+
+ @Override
+ public void startWrapper(Wrapper wrapper) {
+ converter.startWrapper(wrapper);
+ super.startWrapper(wrapper);
+ }
+
+ @Override
+ public void endWrapper(Wrapper wrapper) {
+ converter.endWrapper(wrapper);
+ super.endWrapper(wrapper);
+ }
+
+ @Override
+ public void character(Character c) {
+ converter.character(c);
+ super.character(c);
+ }
+
+ @Override
+ public void characters(char[] data, int start, int length) {
+ converter.characters(data, start, length);
+ super.characters(data, start, length);
+ }
+
+ @Override
+ public void startExternalDocument(ExternalDocument document) {
+ converter.startExternalDocument(document);
+ super.startExternalDocument(document);
+ }
+
+ @Override
+ public void endExternalDocument(ExternalDocument document) {
+ converter.endExternalDocument(document);
+ super.endExternalDocument(document);
+ }
+
+}
+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.accessibility;
-
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-/**
- * A reduced version of the document's FO tree, containing only its logical
- * structure. Used by accessible output formats.
- */
-public final class StructureTree {
-
- private final List pageSequenceStructures = new ArrayList();
-
- /**
- * Package-private default constructor.
- */
- public StructureTree() { }
-
- private static boolean flowOrStaticContentNodes(NodeList nodes) {
- for (int i = 0; i < nodes.getLength(); i++) {
- Node node = nodes.item(i);
- if (node.getNodeType() != Node.ELEMENT_NODE) {
- return false;
- }
- String name = node.getLocalName();
- if (!(name.equals("flow") || name.equals("static-content"))) {
- return false;
- }
- }
- return true;
- }
-
- void addPageSequenceStructure(NodeList structureTree) {
- assert flowOrStaticContentNodes(structureTree);
- pageSequenceStructures.add(structureTree);
- }
-
- /**
- * Returns the list of nodes that are the children of the given page sequence.
- *
- * @param index index of the page sequence, 0-based
- * @return its children nodes
- */
- public NodeList getPageSequence(int index) {
- return (NodeList) pageSequenceStructures.get(index);
- }
-
- /**
- * Returns an XML-like representation of the structure trees.
- * <p>
- * <strong>Note:</strong> use only for debugging purpose, as this method
- * performs non-trivial operations.
- * </p>
- * @return a string representation of this object
- */
- public String toString() {
- try {
- Transformer t = TransformerFactory.newInstance().newTransformer();
- Writer str = new StringWriter();
- for (Iterator iter = pageSequenceStructures.iterator(); iter.hasNext();) {
- NodeList nodes = (NodeList) iter.next();
- for (int i = 0, c = nodes.getLength(); i < c; i++) {
- t.transform(new DOMSource(nodes.item(i)), new StreamResult(str));
- }
- }
- return str.toString();
- } catch (Exception e) {
- return e.toString();
- }
- }
-
-}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+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.apache.fop.fo.FOElementMapping;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fo.extensions.InternalElementMapping;
+import org.apache.fop.render.intermediate.IFConstants;
+
+/**
+ * Converts structure tree events to SAX events.
+ */
+public final class StructureTree2SAXEventAdapter implements StructureTreeEventHandler {
+
+ private final ContentHandler contentHandler;
+
+ private StructureTree2SAXEventAdapter(ContentHandler currentContentHandler) {
+ this.contentHandler = currentContentHandler;
+ }
+
+ /**
+ * Factory method that creates a new instance.
+ * @param contentHandler The handler that receives SAX events
+ */
+ public static StructureTreeEventHandler newInstance(ContentHandler contentHandler) {
+ return new StructureTree2SAXEventAdapter(contentHandler);
+ }
+
+ /** {@inheritDoc} */
+ public void startPageSequence(Locale locale) {
+ try {
+
+ contentHandler.startPrefixMapping(
+ InternalElementMapping.STANDARD_PREFIX, InternalElementMapping.URI);
+ contentHandler.startPrefixMapping(
+ ExtensionElementMapping.STANDARD_PREFIX, ExtensionElementMapping.URI);
+ contentHandler.startElement(IFConstants.NAMESPACE,
+ IFConstants.EL_STRUCTURE_TREE, IFConstants.EL_STRUCTURE_TREE,
+ new AttributesImpl());
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void endPageSequence() {
+ try {
+ contentHandler.endElement(IFConstants.NAMESPACE, IFConstants.EL_STRUCTURE_TREE,
+ IFConstants.EL_STRUCTURE_TREE);
+ contentHandler.endPrefixMapping(
+ ExtensionElementMapping.STANDARD_PREFIX);
+ contentHandler.endPrefixMapping(
+ InternalElementMapping.STANDARD_PREFIX);
+
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void startNode(String name, Attributes attributes) {
+ try {
+ contentHandler.startElement(FOElementMapping.URI, name,
+ FOElementMapping.STANDARD_PREFIX + ":" + name,
+ attributes);
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void endNode(String name) {
+ try {
+ contentHandler.endElement(FOElementMapping.URI, name,
+ FOElementMapping.STANDARD_PREFIX + ":" + name);
+ } catch (SAXException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.accessibility;
-
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.dom.DOMResult;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-import org.apache.fop.util.DelegatingContentHandler;
-
-/**
- * Helper class that re-builds a structure tree from what is stored in an
- * intermediate XML file (IF XML or Area Tree XML).
- */
-public final class StructureTreeBuilder {
-
- private final SAXTransformerFactory factory;
-
- private final StructureTree structureTree = new StructureTree();
-
- /**
- * Creates a new instance.
- *
- * @param factory a factory internally used to build the structures of page
- * sequences
- */
- public StructureTreeBuilder(SAXTransformerFactory factory) {
- this.factory = factory;
- }
-
- /**
- * Returns the structure tree that will result from the parsing.
- *
- * @return the structure tree built by this object
- */
- public StructureTree getStructureTree() {
- return structureTree;
- }
-
- /**
- * Returns a ContenHandler for parsing the structure of a new page sequence.
- * It is assumed that page sequences are being parsed in the document order.
- *
- * @return a handler for parsing the <structure-tree> or
- * <structureTree> element and its descendants
- * @throws SAXException if there is an error when creating the handler
- */
- public ContentHandler getHandlerForNextPageSequence() throws SAXException {
- TransformerHandler structureTreeBuilder;
- try {
- structureTreeBuilder = factory.newTransformerHandler();
- } catch (TransformerConfigurationException e) {
- throw new SAXException(e);
- }
- final DOMResult domResult = new DOMResult();
- structureTreeBuilder.setResult(domResult);
- return new DelegatingContentHandler(structureTreeBuilder) {
-
- public void characters(char[] ch, int start, int length) throws SAXException {
- /*
- * There's no text node in the structure tree. This is just
- * whitespace => ignore
- */
- }
-
- public void endDocument() throws SAXException {
- super.endDocument();
- structureTree.addPageSequenceStructure(domResult.getNode().getFirstChild()
- .getChildNodes());
- }
- };
- }
-
-}
+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.accessibility;
-
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMResult;
-import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
-
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.fop.apps.FOUserAgent;
-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.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;
-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;
-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 class that builds the document's structure tree.
- */
-public class StructureTreeBuildingFOEventHandler extends DelegatingFOEventHandler {
-
- private int idCounter;
-
- private final StructureTree structureTree;
-
- private TransformerHandler structureTreeDOMBuilder;
-
- private DOMResult result;
-
- /** Delegates to either {@link #actualStructureTreeBuilder} or {@link #eventSwallower}. */
- private FOEventHandler structureTreeBuilder;
-
- private FOEventHandler actualStructureTreeBuilder;
-
- /** The descendants of some elements like fo:leader must be ignored. */
- private final FOEventHandler eventSwallower;
-
- private final class StructureTreeBuilder extends FOEventHandler {
-
- public StructureTreeBuilder(FOUserAgent foUserAgent) {
- super(foUserAgent);
- }
-
- @Override
- public void startDocument() throws SAXException {
- }
-
- @Override
- public void endDocument() throws SAXException {
- }
-
- @Override
- public void startPageSequence(PageSequence pageSeq) {
- SAXTransformerFactory transformerFactory =
- (SAXTransformerFactory) TransformerFactory.newInstance();
- try {
- structureTreeDOMBuilder = transformerFactory.newTransformerHandler();
- } catch (TransformerConfigurationException e) {
- throw new RuntimeException(e);
- }
- result = new DOMResult();
- structureTreeDOMBuilder.setResult(result);
- try {
- structureTreeDOMBuilder.startDocument();
- } catch (SAXException e) {
- throw new RuntimeException(e);
- }
- startElement(pageSeq);
- }
-
- @Override
- public void endPageSequence(PageSequence pageSeq) {
- endElement(pageSeq);
- try {
- structureTreeDOMBuilder.endDocument();
- } catch (SAXException e) {
- throw new RuntimeException(e);
- }
- structureTree.addPageSequenceStructure(
- result.getNode().getFirstChild().getChildNodes());
- }
-
- @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);
- }
-
- @Override
- public void startBlockContainer(BlockContainer blc) {
- startElement(blc);
- }
-
- @Override
- public void endBlockContainer(BlockContainer blc) {
- endElement(blc);
- }
-
- @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);
- }
- try {
- structureTreeDOMBuilder.startElement(node.getNamespaceURI(), localName,
- node.getNormalNamespacePrefix() + ":" + localName,
- attributes);
- } catch (SAXException e) {
- throw new RuntimeException(e);
- }
- }
-
- 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();
- try {
- structureTreeDOMBuilder.endElement(node.getNamespaceURI(), localName,
- node.getNormalNamespacePrefix() + ":" + localName);
- } catch (SAXException e) {
- throw new RuntimeException(e);
- }
- }
-
- }
-
- /**
- * Creates a new instance.
- *
- * @param structureTree the object that will hold the structure tree
- * @param delegate the FO event handler that must be wrapped by this instance
- */
- public StructureTreeBuildingFOEventHandler(StructureTree structureTree,
- FOEventHandler delegate) {
- super(delegate);
- this.structureTree = structureTree;
- this.actualStructureTreeBuilder = new StructureTreeBuilder(foUserAgent);
- this.structureTreeBuilder = actualStructureTreeBuilder;
- this.eventSwallower = new FOEventHandler(foUserAgent) { };
- }
-
- @Override
- public void startDocument() throws SAXException {
- structureTreeBuilder.startDocument();
- super.startDocument();
- }
-
- @Override
- public void endDocument() throws SAXException {
- structureTreeBuilder.endDocument();
- super.endDocument();
- }
-
- @Override
- public void startPageSequence(PageSequence pageSeq) {
- structureTreeBuilder.startPageSequence(pageSeq);
- super.startPageSequence(pageSeq);
- }
-
- @Override
- public void endPageSequence(PageSequence pageSeq) {
- structureTreeBuilder.endPageSequence(pageSeq);
- super.endPageSequence(pageSeq);
- }
-
- @Override
- public void startPageNumber(PageNumber pagenum) {
- structureTreeBuilder.startPageNumber(pagenum);
- super.startPageNumber(pagenum);
- }
-
- @Override
- public void endPageNumber(PageNumber pagenum) {
- structureTreeBuilder.endPageNumber(pagenum);
- super.endPageNumber(pagenum);
- }
-
- @Override
- public void startPageNumberCitation(PageNumberCitation pageCite) {
- structureTreeBuilder.startPageNumberCitation(pageCite);
- super.startPageNumberCitation(pageCite);
- }
-
- @Override
- public void endPageNumberCitation(PageNumberCitation pageCite) {
- structureTreeBuilder.endPageNumberCitation(pageCite);
- super.endPageNumberCitation(pageCite);
- }
-
- @Override
- public void startPageNumberCitationLast(PageNumberCitationLast pageLast) {
- structureTreeBuilder.startPageNumberCitationLast(pageLast);
- super.startPageNumberCitationLast(pageLast);
- }
-
- @Override
- public void endPageNumberCitationLast(PageNumberCitationLast pageLast) {
- structureTreeBuilder.endPageNumberCitationLast(pageLast);
- super.endPageNumberCitationLast(pageLast);
- }
-
- @Override
- public void startFlow(Flow fl) {
- structureTreeBuilder.startFlow(fl);
- super.startFlow(fl);
- }
-
- @Override
- public void endFlow(Flow fl) {
- structureTreeBuilder.endFlow(fl);
- super.endFlow(fl);
- }
-
- @Override
- public void startBlock(Block bl) {
- structureTreeBuilder.startBlock(bl);
- super.startBlock(bl);
- }
-
- @Override
- public void endBlock(Block bl) {
- structureTreeBuilder.endBlock(bl);
- super.endBlock(bl);
- }
-
- @Override
- public void startBlockContainer(BlockContainer blc) {
- structureTreeBuilder.startBlockContainer(blc);
- super.startBlockContainer(blc);
- }
-
- @Override
- public void endBlockContainer(BlockContainer blc) {
- structureTreeBuilder.endBlockContainer(blc);
- super.endBlockContainer(blc);
- }
-
- @Override
- public void startInline(Inline inl) {
- structureTreeBuilder.startInline(inl);
- super.startInline(inl);
- }
-
- @Override
- public void endInline(Inline inl) {
- structureTreeBuilder.endInline(inl);
- super.endInline(inl);
- }
-
- @Override
- public void startTable(Table tbl) {
- structureTreeBuilder.startTable(tbl);
- super.startTable(tbl);
- }
-
- @Override
- public void endTable(Table tbl) {
- structureTreeBuilder.endTable(tbl);
- super.endTable(tbl);
- }
-
- @Override
- public void startColumn(TableColumn tc) {
- structureTreeBuilder.startColumn(tc);
- super.startColumn(tc);
- }
-
- @Override
- public void endColumn(TableColumn tc) {
- structureTreeBuilder.endColumn(tc);
- super.endColumn(tc);
- }
-
- @Override
- public void startHeader(TableHeader header) {
- structureTreeBuilder.startHeader(header);
- super.startHeader(header);
- }
-
- @Override
- public void endHeader(TableHeader header) {
- structureTreeBuilder.endHeader(header);
- super.endHeader(header);
- }
-
- @Override
- public void startFooter(TableFooter footer) {
- structureTreeBuilder.startFooter(footer);
- super.startFooter(footer);
- }
-
- @Override
- public void endFooter(TableFooter footer) {
- structureTreeBuilder.endFooter(footer);
- super.endFooter(footer);
- }
-
- @Override
- public void startBody(TableBody body) {
- structureTreeBuilder.startBody(body);
- super.startBody(body);
- }
-
- @Override
- public void endBody(TableBody body) {
- structureTreeBuilder.endBody(body);
- super.endBody(body);
- }
-
- @Override
- public void startRow(TableRow tr) {
- structureTreeBuilder.startRow(tr);
- super.startRow(tr);
- }
-
- @Override
- public void endRow(TableRow tr) {
- structureTreeBuilder.endRow(tr);
- super.endRow(tr);
- }
-
- @Override
- public void startCell(TableCell tc) {
- structureTreeBuilder.startCell(tc);
- super.startCell(tc);
- }
-
- @Override
- public void endCell(TableCell tc) {
- structureTreeBuilder.endCell(tc);
- super.endCell(tc);
- }
-
- @Override
- public void startList(ListBlock lb) {
- structureTreeBuilder.startList(lb);
- super.startList(lb);
- }
-
- @Override
- public void endList(ListBlock lb) {
- structureTreeBuilder.endList(lb);
- super.endList(lb);
- }
-
- @Override
- public void startListItem(ListItem li) {
- structureTreeBuilder.startListItem(li);
- super.startListItem(li);
- }
-
- @Override
- public void endListItem(ListItem li) {
- structureTreeBuilder.endListItem(li);
- super.endListItem(li);
- }
-
- @Override
- public void startListLabel(ListItemLabel listItemLabel) {
- structureTreeBuilder.startListLabel(listItemLabel);
- super.startListLabel(listItemLabel);
- }
-
- @Override
- public void endListLabel(ListItemLabel listItemLabel) {
- structureTreeBuilder.endListLabel(listItemLabel);
- super.endListLabel(listItemLabel);
- }
-
- @Override
- public void startListBody(ListItemBody listItemBody) {
- structureTreeBuilder.startListBody(listItemBody);
- super.startListBody(listItemBody);
- }
-
- @Override
- public void endListBody(ListItemBody listItemBody) {
- structureTreeBuilder.endListBody(listItemBody);
- super.endListBody(listItemBody);
- }
-
- @Override
- public void startStatic(StaticContent staticContent) {
- structureTreeBuilder.startStatic(staticContent);
- super.startStatic(staticContent);
- }
-
- @Override
- public void endStatic(StaticContent statisContent) {
- structureTreeBuilder.endStatic(statisContent);
- super.endStatic(statisContent);
- }
-
- @Override
- public void startMarkup() {
- structureTreeBuilder.startMarkup();
- super.startMarkup();
- }
-
- @Override
- public void endMarkup() {
- structureTreeBuilder.endMarkup();
- super.endMarkup();
- }
-
- @Override
- public void startLink(BasicLink basicLink) {
- structureTreeBuilder.startLink(basicLink);
- super.startLink(basicLink);
- }
-
- @Override
- public void endLink(BasicLink basicLink) {
- structureTreeBuilder.endLink(basicLink);
- super.endLink(basicLink);
- }
-
- @Override
- public void image(ExternalGraphic eg) {
- structureTreeBuilder.image(eg);
- super.image(eg);
- }
-
- @Override
- public void pageRef() {
- structureTreeBuilder.pageRef();
- super.pageRef();
- }
-
- @Override
- public void startInstreamForeignObject(InstreamForeignObject ifo) {
- structureTreeBuilder.startInstreamForeignObject(ifo);
- super.startInstreamForeignObject(ifo);
- }
-
- @Override
- public void endInstreamForeignObject(InstreamForeignObject ifo) {
- structureTreeBuilder.endInstreamForeignObject(ifo);
- super.endInstreamForeignObject(ifo);
- }
-
- @Override
- public void startFootnote(Footnote footnote) {
- structureTreeBuilder.startFootnote(footnote);
- super.startFootnote(footnote);
- }
-
- @Override
- public void endFootnote(Footnote footnote) {
- structureTreeBuilder.endFootnote(footnote);
- super.endFootnote(footnote);
- }
-
- @Override
- public void startFootnoteBody(FootnoteBody body) {
- structureTreeBuilder.startFootnoteBody(body);
- super.startFootnoteBody(body);
- }
-
- @Override
- public void endFootnoteBody(FootnoteBody body) {
- structureTreeBuilder.endFootnoteBody(body);
- super.endFootnoteBody(body);
- }
-
- @Override
- public void startLeader(Leader l) {
- structureTreeBuilder = eventSwallower;
- structureTreeBuilder.startLeader(l);
- super.startLeader(l);
- }
-
- @Override
- public void endLeader(Leader l) {
- structureTreeBuilder.endLeader(l);
- structureTreeBuilder = actualStructureTreeBuilder;
- super.endLeader(l);
- }
-
- @Override
- public void startWrapper(Wrapper wrapper) {
- structureTreeBuilder.startWrapper(wrapper);
- super.startWrapper(wrapper);
- }
-
- @Override
- public void endWrapper(Wrapper wrapper) {
- structureTreeBuilder.endWrapper(wrapper);
- super.endWrapper(wrapper);
- }
-
- @Override
- public void character(Character c) {
- structureTreeBuilder.character(c);
- super.character(c);
- }
-
- @Override
- public void characters(char[] data, int start, int length) {
- structureTreeBuilder.characters(data, start, length);
- super.characters(data, start, length);
- }
-
- @Override
- public void startExternalDocument(ExternalDocument document) {
- structureTreeBuilder.startExternalDocument(document);
- super.startExternalDocument(document);
- }
-
- @Override
- public void endExternalDocument(ExternalDocument document) {
- structureTreeBuilder.endExternalDocument(document);
- super.endExternalDocument(document);
- }
-
-}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+import java.util.Locale;
+
+import org.xml.sax.Attributes;
+
+/**
+ * Receive notifications relating to the structure tree of an FO document.
+ * A structure tree is a reduced version of the document's FO tree, containing only the logical
+ * structure that is used by accessible output formats.
+ */
+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
+ */
+ void startNode(String name, Attributes attributes);
+
+ /**
+ * Ends a structure tree node.
+ * @param name The name of the structure tree node
+ */
+ void endNode(String name);
+
+ /**
+ * Ends a page sequence structure tree node.
+ */
+ void endPageSequence();
+}
import org.apache.fop.Version;
import org.apache.fop.accessibility.Accessibility;
-import org.apache.fop.accessibility.StructureTree;
+import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.events.DefaultEventBroadcaster;
import org.apache.fop.events.Event;
import org.apache.fop.events.EventBroadcaster;
private boolean locatorEnabled = true; // true by default (for error messages).
private boolean conserveMemoryPolicy = false;
private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();
-
- private StructureTree structureTree;
+ private StructureTreeEventHandler structureTreeEventHandler = DummyStructureTreeEventHandler.INSTANCE;
/** Producer: Metadata element for the system/software that produces
* the document. (Some renderers can store this in the document.)
* @param documentHandler the document handler instance to use
*/
public void setDocumentHandlerOverride(IFDocumentHandler documentHandler) {
+ if (isAccessibilityEnabled()) {
+ setStructureTreeEventHandler(documentHandler.getStructureTreeEventHandler());
+ }
this.documentHandlerOverride = documentHandler;
}
}
/**
- * Sets the document's structure tree, for use by accessible output formats.
+ * Sets the document's structure tree event handler, for use by accessible
+ * output formats.
*
- * @param structureTree a simplified version of the FO tree, retaining only
- * its logical structure
+ * @param structureTreeEventHandler The structure tree event handler to set
*/
- public void setStructureTree(StructureTree structureTree) {
- this.structureTree = structureTree;
+ public void setStructureTreeEventHandler(StructureTreeEventHandler structureTreeEventHandler) {
+ this.structureTreeEventHandler = structureTreeEventHandler;
}
/**
- * Returns the document's structure tree, for use by accessible output
- * formats.
+ * Returns the document's structure tree event handler, for use by
+ * accessible output formats.
*
- * @return a simplified version of the FO tree, retaining only its logical
- * structure
+ * @return The structure tree event handler
*/
- public StructureTree getStructureTree() {
- return this.structureTree;
+ public StructureTreeEventHandler getStructureTreeEventHandler() {
+ return this.structureTreeEventHandler;
}
}
// Java
import java.io.OutputStream;
import java.util.List;
+import java.util.Locale;
import org.xml.sax.SAXException;
}
}
+ @Override
+ public void startRoot(Root root) {
+ Locale locale = root.getLocale();
+ if (locale != null) {
+ model.setDocumentLocale(locale);
+ }
+ }
+
/**
* finish the previous pageSequence
*/
// Java
import java.util.List;
+import java.util.Locale;
import org.xml.sax.SAXException;
public PageViewport getPage(int seq, int count) {
return pageSequenceList.get(seq - 1).getPage(count);
}
+
+ /**
+ *
+ * @param locale The locale of the document
+ */
+ public void setDocumentLocale(Locale locale) {
+ }
}
import org.apache.xmlgraphics.util.QName;
import org.apache.fop.ResourceEventProducer;
-import org.apache.fop.accessibility.AccessibilityEventProducer;
-import org.apache.fop.accessibility.StructureTreeBuilder;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background;
import org.apache.fop.area.Trait.InternalLink;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.ElementMappingRegistry;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.ConversionUtils;
import org.apache.fop.util.DefaultErrorListener;
-import org.apache.fop.util.DelegatingContentHandler;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil;
private DOMImplementation domImplementation;
private Locator locator;
-
- private StructureTreeBuilder structureTreeBuilder;
-
- private ContentHandler structureTreeBuilderWrapper;
-
private Attributes pageSequenceAttributes;
- private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {
-
- private StructureTreeBuilderWrapper()
- throws SAXException {
- super(structureTreeBuilder.getHandlerForNextPageSequence());
- }
-
- public void endDocument() throws SAXException {
- super.endDocument();
- startAreaTreeElement("pageSequence", pageSequenceAttributes);
- pageSequenceAttributes = null;
- }
- }
-
public Handler(AreaTreeModel treeModel, FOUserAgent userAgent,
ElementMappingRegistry elementMappingRegistry) {
this.treeModel = treeModel;
makers.put("bookmarkTree", new BookmarkTreeMaker());
makers.put("bookmark", new BookmarkMaker());
makers.put("destination", new DestinationMaker());
-
- if (userAgent.isAccessibilityEnabled()) {
- structureTreeBuilder = new StructureTreeBuilder(tFactory);
- userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
- }
}
private Area findAreaType(Class clazz) {
} else {
boolean handled = true;
if ("".equals(uri)) {
- if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) {
- structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
- pageSequenceAttributes = new AttributesImpl(attributes);
- } else if (localName.equals("structureTree")) {
- if (userAgent.isAccessibilityEnabled()) {
- delegate = structureTreeBuilderWrapper;
- } else {
- /* Delegate to a handler that does nothing */
- delegate = new DefaultHandler();
- }
+ if (localName.equals("structureTree")) {
+
+ /* The area tree parser no longer supports the structure tree. */
+ delegate = new DefaultHandler();
+
delegateStack.push(qName);
delegate.startDocument();
delegate.startElement(uri, localName, qName, attributes);
} else {
- if (pageSequenceAttributes != null) {
- /*
- * This means that no structure-element tag was
- * found in the XML, otherwise a
- * StructureTreeBuilderWrapper object would have
- * been created, which would have reset the
- * pageSequenceAttributes field.
- */
- AccessibilityEventProducer.Provider
- .get(userAgent.getEventBroadcaster())
- .noStructureTreeInXML(this);
- }
handled = startAreaTreeElement(localName, attributes);
}
} else {
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import org.xml.sax.SAXException;
}
}
+ @Override
+ public void setDocumentLocale(Locale locale) {
+ renderer.setDocumentLocale(locale);
+ }
+
/** {@inheritDoc} */
@Override
public void startPageSequence(PageSequence pageSequence) {
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.Root;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fonts.FontInfo;
delegate.endDocument();
}
+ @Override
+ public void startRoot(Root root) {
+ delegate.startRoot(root);
+ }
+
+ @Override
+ public void endRoot(Root root) {
+ delegate.endRoot(root);
+ }
+
@Override
public void startPageSequence(PageSequence pageSeq) {
delegate.startPageSequence(pageSeq);
/** The XSL-FO namespace URI */
public static final String URI = "http://www.w3.org/1999/XSL/Format";
+ /** Standard prefix */
+ public static final String STANDARD_PREFIX = "fo";
+
/**
* Basic constructor; inititializes the namespace URI for the fo: namespace
*/
/** {@inheritDoc} */
public String getStandardPrefix() {
- return "fo";
+ return STANDARD_PREFIX;
}
/** {@inheritDoc} */
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.Root;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.fonts.FontEventAdapter;
import org.apache.fop.fonts.FontInfo;
public void endDocument() throws SAXException {
}
+ public void startRoot(Root root) {
+ }
+
+ public void endRoot(Root root) {
+ }
+
/**
*
* @param pageSeq PageSequence that is starting.
import org.apache.xmlgraphics.util.QName;
-import org.apache.fop.accessibility.StructureTree;
-import org.apache.fop.accessibility.StructureTreeBuildingFOEventHandler;
+import org.apache.fop.accessibility.FO2StructureTreeConverter;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FormattingResults;
foEventHandler = foUserAgent.getRendererFactory().createFOEventHandler(
foUserAgent, outputFormat, stream);
if (userAgent.isAccessibilityEnabled()) {
- StructureTree structureTree = new StructureTree();
- foEventHandler = new StructureTreeBuildingFOEventHandler(structureTree, foEventHandler);
- userAgent.setStructureTree(structureTree);
+ foEventHandler = new FO2StructureTreeConverter(
+ foUserAgent.getStructureTreeEventHandler(), foEventHandler);
}
builderContext = new FOTreeBuilderContext();
builderContext.setPropertyListMaker(new PropertyListMaker() {
// java
import java.util.List;
+import java.util.Locale;
import org.xml.sax.Locator;
private BookmarkTree bookmarkTree = null;
private List<Destination> destinationList;
private List<PageSequence> pageSequences;
+ private Locale locale;
// temporary until above list populated
private boolean pageSequenceFound = false;
super.bind(pList);
commonAccessibility = CommonAccessibility.getInstance(pList);
mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum();
+ String language = pList.get(PR_LANGUAGE).getString();
+ String country = pList.get(PR_COUNTRY).getString();
+ if (isLocalePropertySet(language)) {
+ if (isLocalePropertySet(country)) {
+ locale = new Locale(language, country);
+ } else {
+ locale = new Locale(language);
+ }
+ }
+ }
+
+ private boolean isLocalePropertySet(String property) {
+ return property != null && !property.equals("none");
+ }
+
+ /** {@inheritDoc} */
+ protected void startOfNode() throws FOPException {
+ foEventHandler.startRoot(this);
}
/** {@inheritDoc} */
missingChildElementError("(layout-master-set, declarations?, "
+ "bookmark-tree?, (page-sequence|fox:external-document)+)");
}
+ foEventHandler.endRoot(this);
}
/**
return FO_ROOT;
}
+
+ public Locale getLocale() {
+ return locale;
+ }
+
}
return this.root;
}
- /**
- * Makes sure a Lang entry has been set on the document catalog, setting it
- * to a default value if necessary. When accessibility is enabled the
- * language must be specified for any text element in the document.
- */
- public void enforceLanguageOnRoot() {
- if (root.getLanguage() == null) {
- String fallbackLanguage;
- if (getProfile().getPDFAMode().isPDFA1LevelA()) {
- //According to Annex B of ISO-19005-1:2005(E), section B.2
- fallbackLanguage = "x-unknown";
- } else {
- //No language has been set on the first page-sequence, so fall back to "en".
- fallbackLanguage = "en";
- }
- root.setLanguage(fallbackLanguage);
- }
- }
-
/**
* Get the {@link PDFInfo} object for this document.
*
//---------=== Info and validation methods ===---------
+ private String format(String pattern, Object[] args) {
+ return MessageFormat.format(pattern, args);
+ }
+
private String format(String pattern, Object arg) {
- return MessageFormat.format(pattern, new Object[] {arg});
+ return format(pattern, new Object[] {arg});
}
/** Checks if encryption is allowed. */
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Locale;
+
+import org.apache.fop.util.LanguageTags;
/**
* Class representing a Root (/Catalog) object.
setObjectNumber(objnum);
put("Type", new PDFName("Catalog"));
setRootPages(pages);
+ setLanguage("x-unknown");
}
/** {@inheritDoc} */
* Sets the language identifier of the document.
* @param lang the language identifier of the document.
*/
- public void setLanguage(String lang) {
- if (lang == null) {
- throw new NullPointerException("lang must not be null");
+ public void setLanguage(Locale locale) {
+ if (locale == null) {
+ throw new NullPointerException("locale must not be null");
}
+ setLanguage(LanguageTags.toLanguageTag(locale));
+ }
+
+ private void setLanguage(String lang) {
put("Lang", lang);
}
import java.util.Locale;
-import org.apache.fop.util.XMLUtil;
+import org.apache.fop.util.LanguageTags;
/**
* Class representing a PDF Structure Element.
* @param language a value for the Lang entry
*/
public void setLanguage(Locale language) {
- setLanguage(XMLUtil.toRFC3066(language));
+ setLanguage(LanguageTags.toLanguageTag(language));
}
/**
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import java.util.Set;
import org.w3c.dom.Document;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fonts.FontInfo;
return false;
}
+ /** {@inheritDoc} */
+ public void setDocumentLocale(Locale locale) {
+ }
+
/**
* {@inheritDoc}
*/
// Java
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Locale;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
*/
boolean supportsOutOfOrder();
+ /**
+ *
+ * @param locale Locale of the language
+ */
+ void setDocumentLocale(Locale locale);
+
/**
* Tells the renderer to process an item not explicitly placed on the
* document (e.g., PDF bookmarks). Note - not all renderers will process
package org.apache.fop.render.intermediate;
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.apps.FOUserAgent;
/**
return getContext().getUserAgent();
}
+ /** {@inheritDoc} */
+ public StructureTreeEventHandler getStructureTreeEventHandler() {
+ return DummyStructureTreeEventHandler.INSTANCE;
+ }
+
/** {@inheritDoc} */
public IFDocumentNavigationHandler getDocumentNavigationHandler() {
return null; //By default, this is not supported
}
}
+ /** {@inheritDoc} */
+ public void setDocumentLocale(Locale locale) {
+ }
+
/** {@inheritDoc} */
public void startDocumentHeader() throws IFException {
//nop
public void endPageTrailer() throws IFException {
//nop
}
-
}
String EL_HEADER = "header";
/** element name trailer */
String EL_TRAILER = "trailer";
+ String EL_LOCALE = "locale";
/** element name page-sequence */
String EL_PAGE_SEQUENCE = "page-sequence";
/** element name page */
package org.apache.fop.render.intermediate;
import java.awt.Dimension;
+import java.util.Locale;
import javax.xml.transform.Result;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fonts.FontInfo;
/**
* <p>
* <pre>
* startDocument()
+ * [setDocumentLocale()]
* startDocumentHeader()
* [handleExtension()]*
* endDocumentHeader()
*/
IFDocumentHandlerConfigurator getConfigurator();
+ /**
+ * @return the structure tree builder
+ */
+ StructureTreeEventHandler getStructureTreeEventHandler();
+
/**
* Returns a document navigation handler if this feature is supported.
* @return the document navigation handler or null if not supported
*/
void endDocument() throws IFException;
+ /**
+ * @param locale Locale of the document.
+ */
+ void setDocumentLocale(Locale locale);
+
/**
* Indicates the start of the document header. This method is called right after the
* {@link #startDocument()} method. Extensions sent to this painter between
* @throws IFException if an error occurs while handling this event
*/
void handleExtensionObject(Object extension) throws IFException;
-
- //TODO Prototype the following:
- //ContentHandler handleExtension() throws Exception
}
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.xmlgraphics.util.QName;
import org.apache.fop.accessibility.AccessibilityEventProducer;
-import org.apache.fop.accessibility.StructureTreeBuilder;
+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.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.DOMBuilderContentHandlerFactory;
import org.apache.fop.util.DefaultErrorListener;
-import org.apache.fop.util.DelegatingContentHandler;
+import org.apache.fop.util.LanguageTags;
import org.apache.fop.util.XMLUtil;
/**
private ContentHandler navParser;
- private StructureTreeBuilder structureTreeBuilder;
-
- private ContentHandler structureTreeBuilderWrapper;
+ private ContentHandler structureTreeHandler;
private Attributes pageSequenceAttributes;
- private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {
+ private final class StructureTreeHandler extends DefaultHandler {
- private StructureTreeBuilderWrapper()
- throws SAXException {
- super(structureTreeBuilder.getHandlerForNextPageSequence());
+ private final StructureTreeEventHandler structureTreeEventHandler;
+
+ private StructureTreeHandler(StructureTreeEventHandler structureTreeEventHandler,
+ Locale pageSequenceLanguage) throws SAXException {
+ this.structureTreeEventHandler = structureTreeEventHandler;
+ structureTreeEventHandler.startPageSequence(pageSequenceLanguage);
}
public void endDocument() throws SAXException {
- super.endDocument();
startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
pageSequenceAttributes = null;
}
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+ if (!"structure-tree".equals(localName)) {
+ structureTreeEventHandler.startNode(localName, attributes);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String arqNameg2)
+ throws SAXException {
+ if (!"structure-tree".equals(localName)) {
+ structureTreeEventHandler.endNode(localName);
+ }
+ }
}
public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
this.elementMappingRegistry = elementMappingRegistry;
elementHandlers.put(EL_DOCUMENT, new DocumentHandler());
elementHandlers.put(EL_HEADER, new DocumentHeaderHandler());
+ elementHandlers.put(EL_LOCALE, new LocaleHandler());
elementHandlers.put(EL_TRAILER, new DocumentTrailerHandler());
elementHandlers.put(EL_PAGE_SEQUENCE, new PageSequenceHandler());
elementHandlers.put(EL_PAGE, new PageHandler());
elementHandlers.put(EL_LINE, new LineHandler());
elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
elementHandlers.put(EL_IMAGE, new ImageHandler());
-
- if (userAgent.isAccessibilityEnabled()) {
- structureTreeBuilder = new StructureTreeBuilder(tFactory);
- userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
- }
}
private void establishForeignAttributes(Map<QName, String> foreignAttributes) {
if (NAMESPACE.equals(uri)) {
if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) {
pageSequenceAttributes = new AttributesImpl(attributes);
- structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
+ Locale language = getLanguage(attributes);
+ structureTreeHandler = new StructureTreeHandler(
+ userAgent.getStructureTreeEventHandler(), language);
+
} else if (localName.equals(EL_STRUCTURE_TREE)) {
if (userAgent.isAccessibilityEnabled()) {
- delegate = structureTreeBuilderWrapper;
+ delegate = structureTreeHandler;
} else {
/* Delegate to a handler that does nothing */
delegate = new DefaultHandler();
}
}
+ private static Locale getLanguage(Attributes attributes) {
+ String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
+ return (xmllang == null) ? null : LanguageTags.toLocale(xmllang);
+ }
+
private boolean startIFElement(String localName, Attributes attributes)
throws SAXException {
lastAttributes = new AttributesImpl(attributes);
}
+ private class LocaleHandler extends AbstractElementHandler {
+ public void startElement(Attributes attributes) throws IFException {
+ documentHandler.setDocumentLocale(getLanguage(attributes));
+ }
+ }
+
private class DocumentTrailerHandler extends AbstractElementHandler {
public void startElement(Attributes attributes) throws IFException {
public void startElement(Attributes attributes) throws IFException {
String id = attributes.getValue("id");
- String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
- if (xmllang != null) {
- documentHandler.getContext().setLanguage(
- XMLUtil.convertRFC3066ToLocale(xmllang));
+ Locale language = getLanguage(attributes);
+ if (language != null) {
+ documentHandler.getContext().setLanguage(language);
}
Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
establishForeignAttributes(foreignAttributes);
import org.apache.fop.Version;
import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Area;
import org.apache.fop.area.AreaTreeObject;
import org.apache.fop.area.inline.Image;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.fo.extensions.ExtensionAttachment;
*/
protected IFDocumentHandler createDefaultDocumentHandler() {
IFSerializer serializer = new IFSerializer();
- serializer.setContext(new IFContext(getUserAgent()));
+ FOUserAgent userAgent = getUserAgent();
+ serializer.setContext(new IFContext(userAgent));
+ if (userAgent.isAccessibilityEnabled()) {
+ userAgent.setStructureTreeEventHandler(serializer.getStructureTreeEventHandler());
+ }
return serializer;
}
log.debug("Rendering finished.");
}
+ @Override
+ public void setDocumentLocale(Locale locale) {
+ documentHandler.setDocumentLocale(locale);
+ }
+
/** {@inheritDoc} */
public void processOffDocumentItem(OffDocumentItem odi) {
if (odi instanceof DestinationData) {
import java.util.Map;
import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.apache.xmlgraphics.util.QName;
import org.apache.xmlgraphics.util.XMLizable;
-import org.apache.fop.accessibility.StructureTree;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.DOM2SAX;
+import org.apache.fop.util.LanguageTags;
import org.apache.fop.util.XMLConstants;
import org.apache.fop.util.XMLUtil;
+
/**
* IFPainter implementation that serializes the intermediate format to XML.
*/
private String currentID = "";
- /**
- * Default constructor.
- */
- public IFSerializer() {
- }
+ private IFStructureTreeBuilder structureTreeBuilder;
/** {@inheritDoc} */
@Override
}
}
+ @Override
+ public StructureTreeEventHandler getStructureTreeEventHandler() {
+ if (structureTreeBuilder == null) {
+ structureTreeBuilder = new IFStructureTreeBuilder();
+ }
+ return structureTreeBuilder;
+ }
+
/** {@inheritDoc} */
@Override
public void startDocument() throws IFException {
}
}
+ @Override
+ public void setDocumentLocale(Locale locale) {
+ AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA,
+ LanguageTags.toLanguageTag(locale));
+ try {
+ handler.startElement(EL_LOCALE, atts);
+ handler.endElement(EL_LOCALE);
+ } catch (SAXException e) {
+ throw new RuntimeException("Unable to create the " + EL_LOCALE + " element.", e);
+ }
+ }
+
/** {@inheritDoc} */
@Override
public void startDocumentHeader() throws IFException {
Locale lang = getContext().getLanguage();
if (lang != null) {
atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA,
- XMLUtil.toRFC3066(lang));
+ LanguageTags.toLanguageTag(lang));
}
XMLUtil.addAttribute(atts, XMLConstants.XML_SPACE, "preserve");
addForeignAttributes(atts);
handler.startElement(EL_PAGE_SEQUENCE, atts);
if (this.getUserAgent().isAccessibilityEnabled()) {
- StructureTree structureTree = getUserAgent().getStructureTree();
- handler.startElement(EL_STRUCTURE_TREE); // add structure tree
- NodeList nodes = structureTree.getPageSequence(pageSequenceIndex++);
- for (int i = 0, n = nodes.getLength(); i < n; i++) {
- Node node = nodes.item(i);
- new DOM2SAX(handler).writeFragment(node);
- }
- handler.endElement(EL_STRUCTURE_TREE);
+ assert (structureTreeBuilder != null);
+ structureTreeBuilder.replayEventsForPageSequence(handler, pageSequenceIndex++);
}
} catch (SAXException e) {
throw new IFException("SAX error in startPageSequence()", e);
/** {@inheritDoc} */
public void endPageSequence() throws IFException {
try {
+
handler.endElement(EL_PAGE_SEQUENCE);
} catch (SAXException e) {
throw new IFException("SAX error in endPageSequence()", e);
throw new IFException("SAX error serializing object", e);
}
}
-
}
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
IFSerializer handler = new IFSerializer();
handler.setContext(new IFContext(ua));
+ if (ua.isAccessibilityEnabled()) {
+ ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler());
+ }
return handler;
}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.fop.accessibility.StructureTree2SAXEventAdapter;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
+
+/**
+ * Saves structure tree events as SAX events in order to replay them when it's
+ * time to stream the structure tree to the output.
+ */
+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);
+ }
+
+ /** {@inheritDoc} */
+ public void endPageSequence() {
+ delegate.endPageSequence();
+ }
+
+ /** {@inheritDoc} */
+ public void startNode(String name, Attributes attributes) {
+ delegate.startNode(name, attributes);
+ }
+
+ /** {@inheritDoc} */
+ public void endNode(String name) {
+ delegate.endNode(name);
+ }
+
+ /** A SAX handler that records events to replay them later. */
+ static class SAXEventRecorder extends DefaultHandler {
+
+ private final List<SAXEventRecorder.Event> events = new ArrayList<SAXEventRecorder.Event>();
+
+ private abstract static class Event {
+ abstract void replay(ContentHandler handler) throws SAXException;
+ }
+
+ private abstract static class Element extends SAXEventRecorder.Event {
+
+ protected final String uri;
+ protected final String localName;
+ protected final String qName;
+
+ private Element(String uri, String localName, String qName) {
+ this.uri = uri;
+ this.localName = localName;
+ this.qName = qName;
+ }
+ }
+
+ private static final class StartElement extends SAXEventRecorder.Element {
+
+ private final Attributes attributes;
+
+ private StartElement(String uri, String localName, String qName,
+ Attributes attributes) {
+ super(uri, localName, qName);
+ this.attributes = attributes;
+ }
+
+ @Override
+ void replay(ContentHandler handler) throws SAXException {
+ handler.startElement(uri, localName, qName, attributes);
+ }
+ }
+
+ private static final class EndElement extends SAXEventRecorder.Element {
+
+ private EndElement(String uri, String localName, String qName) {
+ super(uri, localName, qName);
+ }
+
+ @Override
+ void replay(ContentHandler handler) throws SAXException {
+ handler.endElement(uri, localName, qName);
+ }
+ }
+
+ private static final class StartPrefixMapping extends SAXEventRecorder.Event {
+
+ protected final String prefix;
+ protected final String uri;
+
+ private StartPrefixMapping(String prefix, String uri) {
+ this.prefix = prefix;
+ this.uri = uri;
+ }
+
+ @Override
+ void replay(ContentHandler handler) throws SAXException {
+ handler.startPrefixMapping(prefix, uri);
+ }
+ }
+
+ private static final class EndPrefixMapping extends SAXEventRecorder.Event {
+
+ protected final String prefix;
+
+ private EndPrefixMapping(String prefix) {
+ this.prefix = prefix;
+ }
+
+ @Override
+ void replay(ContentHandler handler) throws SAXException {
+ handler.endPrefixMapping(prefix);
+ }
+ }
+
+ @Override
+ 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.
+ *
+ * @param handler {@code ContentHandler} to replay events on
+ */
+ public void replay(ContentHandler handler) throws SAXException {
+ for (SAXEventRecorder.Event e : events) {
+ e.replay(handler);
+ }
+ }
+ }
+}
package org.apache.fop.render.intermediate.util;
import java.awt.Dimension;
+import java.util.Locale;
import javax.xml.transform.Result;
+import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.render.intermediate.IFContext;
import org.apache.fop.render.intermediate.IFDocumentHandler;
return this.delegate.getDocumentNavigationHandler();
}
+ /** {@inheritDoc} */
+ public StructureTreeEventHandler getStructureTreeEventHandler() {
+ return DummyStructureTreeEventHandler.INSTANCE;
+ }
+
/** {@inheritDoc} */
public void setResult(Result result) throws IFException {
this.delegate.setResult(result);
this.delegate.startDocument();
}
+ /** {@inheritDoc} */
+ public void setDocumentLocale(Locale locale) {
+ this.delegate.setDocumentLocale(locale);
+
+ }
+
/** {@inheritDoc} */
public void startDocumentHeader() throws IFException {
this.delegate.startDocumentHeader();
this.delegate.handleExtensionObject(extension);
}
-}
\ No newline at end of file
+}
import java.util.HashMap;
import java.util.Map;
-import org.w3c.dom.Node;
-
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.pdf.PDFName;
import org.apache.fop.pdf.PDFObject;
/**
* Standard structure types defined by the PDF Reference, Fourth Edition (PDF 1.5).
*/
- private static final Map STANDARD_STRUCTURE_TYPES = new HashMap();
+ private static final Map<String, PDFName> STANDARD_STRUCTURE_TYPES = new HashMap<String, PDFName>();
- private static final Map DEFAULT_MAPPINGS = new java.util.HashMap();
+ private static final Map<String, Mapper> DEFAULT_MAPPINGS = new java.util.HashMap<String, Mapper>();
private static final PDFName THEAD;
private static final PDFName NON_STRUCT;
* @return the structure type or null if no match could be found
*/
public static PDFName mapFormattingObject(String fo, PDFObject parent) {
- Mapper mapper = (Mapper)DEFAULT_MAPPINGS.get(fo);
+ Mapper mapper = (Mapper) DEFAULT_MAPPINGS.get(fo);
if (mapper != null) {
return mapper.getStructureType(parent);
} else {
}
}
- public static PDFName mapFormattingObject(Node fo, PDFObject parent,
- EventBroadcaster eventBroadcaster) {
+ /**
+ * Maps a Formatting Object to a PDFName representing the associated structure type.
+ * @param fo the formatting object's local name
+ * @param role the value of the formatting object's role property
+ * @param parent the parent of the structure element to be mapped
+ * @param eventBroadcaster the event broadcaster
+ * @return the structure type or null if no match could be found
+ */
+ public static PDFName mapFormattingObject(String fo, String role,
+ PDFObject parent, EventBroadcaster eventBroadcaster) {
PDFName type = null;
- Node role = fo.getAttributes().getNamedItemNS(null, "role");
if (role == null) {
- type = mapFormattingObject(fo.getLocalName(), parent);
+ type = mapFormattingObject(fo, parent);
} else {
- String customType = role.getNodeValue();
- type = (PDFName) STANDARD_STRUCTURE_TYPES.get(customType);
+ type = (PDFName) STANDARD_STRUCTURE_TYPES.get(role);
if (type == null) {
- String foName = fo.getLocalName();
- type = mapFormattingObject(foName, parent);
+ type = mapFormattingObject(fo, parent);
PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo,
- foName, customType, type.toString().substring(1));
+ fo, role, type.toString().substring(1));
}
}
assert type != null;
return type;
}
- private static interface Mapper {
+ private interface Mapper {
PDFName getStructureType(PDFObject parent);
}
public PDFName getStructureType(PDFObject parent) {
PDFStructElem grandParent = (PDFStructElem)
- ((PDFStructElem)parent).getParentStructElem();
+ ((PDFStructElem) parent).getParentStructElem();
//TODO What to do with cells from table-footer? Currently they are mapped on TD.
PDFName type;
if (THEAD.equals(grandParent.getStructureType())) {
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
-import org.w3c.dom.NodeList;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.xmp.Metadata;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.fo.extensions.xmp.XMPMetadata;
import org.apache.fop.pdf.PDFAnnotList;
import org.apache.fop.render.extensions.prepress.PageScale;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFContext;
-import org.apache.fop.render.intermediate.IFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment;
-import org.apache.fop.util.XMLUtil;
/**
- * {@link IFDocumentHandler} implementation that produces PDF.
+ * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that produces PDF.
*/
public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
/** logging instance */
private static Log log = LogFactory.getLog(PDFDocumentHandler.class);
- private int pageSequenceIndex;
-
private boolean accessEnabled;
private PDFLogicalStructureHandler logicalStructureHandler;
+ private PDFStructureTreeBuilder structureTreeBuilder;
+
/** the PDF Document being created */
protected PDFDocument pdfDoc;
protected PageReference currentPageRef;
/** Used for bookmarks/outlines. */
- protected Map<Integer, PageReference> pageReferences
- = new java.util.HashMap<Integer, PageReference>();
+ protected Map<Integer, PageReference> pageReferences = new HashMap<Integer, PageReference>();
private final PDFDocumentNavigationHandler documentNavigationHandler
= new PDFDocumentNavigationHandler(this);
this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream);
this.accessEnabled = getUserAgent().isAccessibilityEnabled();
if (accessEnabled) {
- pdfDoc.getRoot().makeTagged();
- logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc,
- getUserAgent().getEventBroadcaster());
+ setupAccessibility();
}
} catch (IOException e) {
throw new IFException("I/O error in startDocument()", e);
}
}
+ private void setupAccessibility() {
+ pdfDoc.getRoot().makeTagged();
+ logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
+ // TODO this is ugly. All the necessary information should be available
+ // at creation time in order to enforce immutability
+ structureTreeBuilder.setPdfFactory(pdfDoc.getFactory());
+ structureTreeBuilder.setLogicalStructureHandler(logicalStructureHandler);
+ structureTreeBuilder.setEventBroadcaster(getUserAgent().getEventBroadcaster());
+ }
+
/** {@inheritDoc} */
public void endDocumentHeader() throws IFException {
pdfUtil.generateDefaultXMPMetadata();
/** {@inheritDoc} */
public void startPageSequence(String id) throws IFException {
- //TODO page sequence title
-
- if (this.pdfDoc.getRoot().getLanguage() == null
- && getContext().getLanguage() != null) {
- //No document-level language set, so we use the first page-sequence's language
- this.pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(getContext().getLanguage()));
- }
-
- if (accessEnabled) {
- NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
- logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage());
- }
+ //nop
}
/** {@inheritDoc} */
/** {@inheritDoc} */
public void handleExtensionObject(Object extension) throws IFException {
if (extension instanceof XMPMetadata) {
- pdfUtil.renderXMPMetadata((XMPMetadata)extension);
+ pdfUtil.renderXMPMetadata((XMPMetadata) extension);
} else if (extension instanceof Metadata) {
- XMPMetadata wrapper = new XMPMetadata(((Metadata)extension));
+ XMPMetadata wrapper = new XMPMetadata(((Metadata) extension));
pdfUtil.renderXMPMetadata(wrapper);
} else if (extension instanceof PDFEmbeddedFileExtensionAttachment) {
PDFEmbeddedFileExtensionAttachment embeddedFile
}
}
+ /** {@inheritDoc} */
+ public void setDocumentLocale(Locale locale) {
+ pdfDoc.getRoot().setLanguage(locale);
+ }
+
PageReference getPageReference(int pageIndex) {
return this.pageReferences.get(Integer.valueOf(pageIndex));
}
}
}
+ @Override
+ public StructureTreeEventHandler getStructureTreeEventHandler() {
+ if (structureTreeBuilder == null) {
+ structureTreeBuilder = new PDFStructureTreeBuilder();
+ }
+ return structureTreeBuilder;
+ }
}
public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
PDFDocumentHandler handler = new PDFDocumentHandler();
handler.setContext(new IFContext(ua));
+ if (ua.isAccessibilityEnabled()) {
+ ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler());
+ }
return handler;
}
import java.util.Locale;
import java.util.Map;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-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.PDFArray;
import org.apache.fop.pdf.PDFDictionary;
import org.apache.fop.pdf.PDFDocument;
private final PDFDocument pdfDoc;
- private final EventBroadcaster eventBroadcaster;
-
/**
* Map of references to the corresponding structure elements.
*/
- private final Map structTreeMap = new HashMap();
+ private final Map<String, PDFStructElem> structTreeMap = new HashMap<String, PDFStructElem>();
private final PDFParentTree parentTree = new PDFParentTree();
*
* @param pdfDoc a document
*/
- PDFLogicalStructureHandler(PDFDocument pdfDoc, EventBroadcaster eventBroadcaster) {
+ PDFLogicalStructureHandler(PDFDocument pdfDoc) {
this.pdfDoc = pdfDoc;
- this.eventBroadcaster = eventBroadcaster;
PDFStructTreeRoot structTreeRoot = pdfDoc.getFactory().makeStructTreeRoot(parentTree);
rootStructureElement = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot);
structTreeRoot.addKid(rootStructureElement);
}
- /**
- * Converts the given structure tree into PDF.
- *
- * @param structureTree the structure tree of the current page sequence
- * @param language language set on the page sequence
- */
- void processStructureTree(NodeList structureTree, Locale language) {
- pdfDoc.enforceLanguageOnRoot();
+
+ PDFStructElem createPageSequence(Locale language) {
PDFStructElem structElemPart = pdfDoc.getFactory().makeStructureElement(
FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement),
rootStructureElement);
if (language != null) {
structElemPart.setLanguage(language);
}
-
- for (int i = 0, n = structureTree.getLength(); i < n; i++) {
- Node node = structureTree.item(i);
- assert node.getLocalName().equals("flow")
- || node.getLocalName().equals("static-content");
- PDFStructElem structElemSect = pdfDoc.getFactory().makeStructureElement(
- FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), structElemPart),
- structElemPart);
- structElemPart.addKid(structElemSect);
- NodeList childNodes = node.getChildNodes();
- for (int j = 0, m = childNodes.getLength(); j < m; j++) {
- processNode(childNodes.item(j), structElemSect, true);
- }
- }
- }
-
- private void processNode(Node node, PDFStructElem parent, boolean addKid) {
- PDFStructElem structElem = pdfDoc.getFactory().makeStructureElement(
- FOToPDFRoleMap.mapFormattingObject(node, parent, eventBroadcaster), parent);
- // TODO necessary? If a page-sequence is empty (e.g., contains a single
- // empty fo:block), should the block still be added to the structure
- // tree? This is not being done for descendant empty elements...
- if (addKid) {
- parent.addKid(structElem);
- }
- String nodeName = node.getLocalName();
- if (nodeName.equals("external-graphic") || nodeName.equals("instream-foreign-object")) {
- Node altTextNode = node.getAttributes().getNamedItemNS(
- ExtensionElementMapping.URI, "alt-text");
- if (altTextNode != null) {
- structElem.put("Alt", altTextNode.getNodeValue());
- } else {
- structElem.put("Alt", "No alternate text specified");
- }
- }
- Node attr = node.getAttributes().getNamedItemNS(InternalElementMapping.URI, "ptr");
- if (attr != null) {
- String ptr = attr.getNodeValue();
- structTreeMap.put(ptr, structElem);
- }
- NodeList nodes = node.getChildNodes();
- for (int i = 0, n = nodes.getLength(); i < n; i++) {
- processNode(nodes.item(i), structElem, false);
- }
+ return structElemPart;
}
private int getNextParentTreeKey() {
parent.addKid(contentItem);
}
+ void addStructurePointer(String ptr, PDFStructElem structElem) {
+ structTreeMap.put(ptr, structElem);
+ }
+
}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.pdf;
+
+import java.util.LinkedList;
+import java.util.Locale;
+
+import org.xml.sax.Attributes;
+
+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;
+
+class PDFStructureTreeBuilder implements StructureTreeEventHandler {
+
+ private PDFFactory pdfFactory;
+
+ private PDFLogicalStructureHandler logicalStructureHandler;
+
+ private EventBroadcaster eventBroadcaster;
+
+ private LinkedList<PDFStructElem> ancestors = new LinkedList<PDFStructElem>();
+
+ void setPdfFactory(PDFFactory pdfFactory) {
+ this.pdfFactory = pdfFactory;
+ }
+
+ void setLogicalStructureHandler(PDFLogicalStructureHandler logicalStructureHandler) {
+ this.logicalStructureHandler = logicalStructureHandler;
+ }
+
+ void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
+ this.eventBroadcaster = eventBroadcaster;
+ }
+
+ public void startPageSequence(Locale locale) {
+ ancestors = new LinkedList<PDFStructElem>();
+ ancestors.add(logicalStructureHandler.createPageSequence(locale));
+ }
+
+ public void endPageSequence() {
+ }
+
+ public void 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);
+ }
+
+ 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");
+ }
+ }
+ ancestors.addFirst(created);
+ }
+
+ public void endNode(String name) {
+ ancestors.removeFirst();
+ }
+
+}
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import org.xml.sax.SAXException;
import org.apache.xmlgraphics.util.QName;
import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.Leader;
import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.SpaceArea;
import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.inline.InlineViewport;
import org.apache.fop.area.inline.WordArea;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.extensions.ExtensionAttachment;
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.fo.extensions.InternalElementMapping;
import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererContext;
import org.apache.fop.render.XMLHandler;
import org.apache.fop.util.ColorUtil;
-import org.apache.fop.util.DOM2SAX;
/**
* Renderer that renders areas to XML for debugging purposes.
}
transferForeignObjects(pageSequence);
startElement("pageSequence", atts);
- if (this.getUserAgent().isAccessibilityEnabled()) {
- String structureTreeElement = "structureTree";
- startElement(structureTreeElement);
- try {
- this.handler.startPrefixMapping("foi", InternalElementMapping.URI);
- this.handler.startPrefixMapping("fox", ExtensionElementMapping.URI);
- NodeList nodes = getUserAgent().getStructureTree().getPageSequence(
- pageSequenceIndex++);
- for (int i = 0, n = nodes.getLength(); i < n; i++) {
- Node node = nodes.item(i);
- try {
- new DOM2SAX(handler).writeFragment(node);
- } catch (SAXException e) {
- handleSAXException(e);
- }
- }
- this.handler.endPrefixMapping("fox");
- this.handler.endPrefixMapping("foi");
- } catch (SAXException se) {
- handleSAXException(se);
- }
- endElement(structureTreeElement);
- }
handleExtensionAttachments(pageSequence.getExtensionAttachments());
LineArea seqTitle = pageSequence.getTitle();
if (seqTitle != null) {
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import java.util.Locale;
+
+/**
+ * Provides utility methods for manipulating language tags compliant with the
+ * RFC 3066 specification available at http://www.ietf.org/rfc/rfc3066.txt. A
+ * typical language tag is a 2-letter language code sometimes followed by a country
+ * code. For example: en, en-US.
+ */
+public final class LanguageTags {
+
+ private LanguageTags() {
+ }
+
+ /**
+ * Converts the given locale to an RFC 3066 compliant language tag.
+ *
+ * @param locale a locale
+ * @return the corresponding language tag
+ * @throws NullPointerException if the specified locale is null
+ */
+ public static String toLanguageTag(Locale locale) {
+ StringBuffer sb = new StringBuffer(5);
+ sb.append(locale.getLanguage());
+ String country = locale.getCountry();
+ if (country.length() > 0) {
+ sb.append('-');
+ sb.append(country);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Converts an RFC 3066 compliant language tag to a locale.
+ *
+ * @throws NullPointerException if the specified language tag is null
+ */
+ public static Locale toLocale(String languageTag) {
+ String[] parts = languageTag.split("-");
+ if (parts.length == 1) {
+ return new Locale(parts[0]);
+ } else {
+ return new Locale(parts[0], parts[1]);
+ }
+ }
+}
import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
-import java.util.Locale;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
atts.addAttribute("", localName, localName, XMLUtil.CDATA, value);
}
- /**
- * Converts a {@link Locale} instance to an RFC 3066 compliant language identifier.
- * @param language the language
- * @return the formatted language identifier
- */
- public static String toRFC3066(Locale language) {
- if (language == null || language.getLanguage().length() == 0) {
- return null;
- }
- StringBuffer sb = new StringBuffer();
- sb.append(language.getLanguage());
- if (language.getCountry().length() > 0) {
- sb.append('-');
- sb.append(language.getCountry());
- }
- return sb.toString();
- }
-
- /**
- * Converts an RFC 3066 compliant language identifier to a {@link Locale} instance.
- * @param lang the language string
- * @return the converted locale instance
- */
- public static Locale convertRFC3066ToLocale(String lang) {
- if (lang == null || lang.length() == 0) {
- return null;
- }
- String[] parts = lang.split("-");
- if (parts.length == 1) {
- return new Locale(parts[0]);
- } else {
- return new Locale(parts[0], parts[1]);
- }
- }
-
}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<fop version="1.0">
- <accessibility>true</accessibility>
- <source-resolution>144</source-resolution>
- <use-cache>false</use-cache>
- <font-base>../resources/fonts/</font-base>
- <renderers>
- <renderer mime="application/pdf">
- <filterList>
- <value>null</value>
- </filterList>
- <filterList type="image">
- <value>flate</value>
- <value>ascii-85</value>
- </filterList>
- <fonts>
- <font embed-url="DejaVuLGCSerif.ttf">
- <font-triplet name="DejaVu" style="normal" weight="normal"/>
- </font>
- </fonts>
- </renderer>
- </renderers>
-</fop>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<fop version="1.0">
- <prefer-renderer>true</prefer-renderer>
- <accessibility>true</accessibility>
- <source-resolution>144</source-resolution>
- <use-cache>false</use-cache>
- <font-base>../resources/fonts/</font-base>
- <renderers>
- <renderer mime="application/pdf">
- <filterList>
- <value>null</value>
- </filterList>
- <filterList type="image">
- <value>flate</value>
- <value>ascii-85</value>
- </filterList>
- <fonts>
- <font embed-url="DejaVuLGCSerif.ttf">
- <font-triplet name="DejaVu" style="normal" weight="normal"/>
- </font>
- </fonts>
- </renderer>
- </renderers>
-</fop>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<fop version="1.0">
+ <accessibility>true</accessibility>
+ <source-resolution>144</source-resolution>
+ <use-cache>false</use-cache>
+ <font-base>../resources/fonts/</font-base>
+ <renderers>
+ <renderer mime="application/pdf">
+ <filterList>
+ <value>null</value>
+ </filterList>
+ <filterList type="image">
+ <value>flate</value>
+ <value>ascii-85</value>
+ </filterList>
+ <fonts>
+ <font embed-url="DejaVuLGCSerif.ttf">
+ <font-triplet name="DejaVu" style="normal" weight="normal"/>
+ </font>
+ </fonts>
+ </renderer>
+ </renderers>
+</fop>
CharactersetEncoderTest.class,
org.apache.fop.render.afp.AFPTestSuite.class,
PSTestSuite.class,
- MinOptMaxTest.class
+ MinOptMaxTest.class,
+ org.apache.fop.render.intermediate.IFStructureTreeBuilderTestCase.class
})
public class StandardTestSuite {
}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+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.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.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.FODocumentParser;
+import org.apache.fop.fo.FODocumentParser.FOEventHandlerFactory;
+import org.apache.fop.fo.FOEventHandler;
+import org.apache.fop.fo.LoadingException;
+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;
+ }
+ }
+
+ public void skippedComparison(Node control, Node test) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+ }
+
+ private static final String STRUCTURE_TREE_SEQUENCE_NAME = "structure-tree-sequence";
+
+ @Test
+ public void testConverter() throws Exception {
+ DOMResult expectedStructureTree = loadExpectedStructureTree();
+ DOMResult actualStructureTree = buildActualStructureTree();
+ final Diff diff = createDiff(expectedStructureTree, actualStructureTree);
+ assertTrue(diff.toString(), diff.similar());
+ }
+
+ private static DOMResult loadExpectedStructureTree() {
+ DOMResult expectedStructureTree = new DOMResult();
+ runXSLT(getXsltInputStream(), 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 {
+ Transformer transformer = TransformerFactory.newInstance()
+ .newTransformer(new StreamSource(xslt));
+ transformer.transform(fo, result);
+ } catch (TransformerConfigurationException e) {
+ throw new RuntimeException(e);
+ } catch (TransformerException e) {
+ throw new RuntimeException(e);
+ } finally {
+ closeStream(xslt);
+ closeStream(doc);
+ }
+ }
+
+ private static void closeStream(InputStream stream) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static DOMResult buildActualStructureTree() throws Exception {
+ DOMResult actualStructureTree = new DOMResult();
+ createStructureTreeFromDocument(getFoInputStream(), actualStructureTree);
+ return actualStructureTree;
+ }
+
+ private static void createStructureTreeFromDocument(InputStream foInputStream,
+ DOMResult domResult) throws Exception {
+ TransformerHandler tHandler = createTransformerHandler(domResult);
+ startStructureTreeSequence(tHandler);
+ StructureTreeEventHandler structureTreeEventHandler
+ = StructureTree2SAXEventAdapter.newInstance(tHandler);
+ FODocumentParser documentParser = createDocumentParser(structureTreeEventHandler);
+ FOUserAgent userAgent = createFOUserAgent(documentParser);
+ parseDocument(foInputStream, documentParser, userAgent);
+ endStructureTreeSequence(tHandler);
+ }
+
+ private static TransformerHandler createTransformerHandler(DOMResult domResult)
+ throws TransformerConfigurationException, TransformerFactoryConfigurationError {
+ SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+ TransformerHandler transformerHandler = factory.newTransformerHandler();
+ transformerHandler.setResult(domResult);
+ return transformerHandler;
+ }
+
+ private static void startStructureTreeSequence(TransformerHandler tHandler) throws SAXException {
+ tHandler.startDocument();
+ tHandler.startElement("", STRUCTURE_TREE_SEQUENCE_NAME, STRUCTURE_TREE_SEQUENCE_NAME,
+ new AttributesImpl());
+ }
+
+ private static FODocumentParser createDocumentParser(
+ final StructureTreeEventHandler structureTreeEventHandler) {
+ return FODocumentParser.newInstance(new FOEventHandlerFactory() {
+ public FOEventHandler newFOEventHandler(FOUserAgent foUserAgent) {
+ return new FO2StructureTreeConverter(structureTreeEventHandler,
+ new DummyFOEventHandler(foUserAgent));
+ }
+ });
+ }
+
+ private static FOUserAgent createFOUserAgent(FODocumentParser documentParser) {
+ FOUserAgent userAgent = documentParser.createFOUserAgent();
+ userAgent.setAccessibility(true);
+ return userAgent;
+ }
+
+ private static void parseDocument(InputStream foInputStream, FODocumentParser documentParser,
+ FOUserAgent userAgent) throws FOPException, LoadingException {
+ try {
+ documentParser.parse(foInputStream, userAgent);
+ } finally {
+ closeStream(foInputStream);
+ }
+ }
+
+ private static void endStructureTreeSequence(TransformerHandler tHandler) throws SAXException {
+ tHandler.endElement("", STRUCTURE_TREE_SEQUENCE_NAME, STRUCTURE_TREE_SEQUENCE_NAME);
+ tHandler.endDocument();
+ }
+
+ private static Diff createDiff(DOMResult expected, DOMResult actual) {
+ Diff diff = new Diff(getDocument(expected), getDocument(actual));
+ diff.overrideDifferenceListener(new IgnoringPtrDifferenceListener());
+ return diff;
+ }
+
+ private static Document getDocument(DOMResult result) {
+ return (Document) result.getNode();
+ }
+}
--- /dev/null
+<?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"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
+ xmlns:foi="http://xmlgraphics.apache.org/fop/internal">
+
+ <xsl:output method="xml" indent="no"/>
+
+ <xsl:template name="copy">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+
+ <!-- Ignore fo:root -->
+ <xsl:template match="fo:root">
+ <structure-tree-sequence>
+ <xsl:apply-templates/>
+ </structure-tree-sequence>
+ </xsl:template>
+
+ <!-- fo:page-sequence maps to structure-tree -->
+ <xsl:template match="fo:page-sequence">
+ <structure-tree xmlns="http://xmlgraphics.apache.org/fop/intermediate">
+ <xsl:apply-templates/>
+ </structure-tree>
+ </xsl:template>
+
+
+ <!-- Declarations and Pagination and Layout Formatting Objects -->
+ <xsl:template match="fo:static-content|fo:flow">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Block-level Formatting Objects -->
+ <xsl:template match="fo:block|fo:block-container">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Inline-level Formatting Objects -->
+ <xsl:template match="fo:character|fo:inline|fo:inline-container">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <xsl:template match="fo:external-graphic|fo:instream-foreign-object">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <xsl:template match="fo:page-number|fo:page-number-citation|fo:page-number-citation-last">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Formatting Objects for Tables -->
+ <xsl:template match="fo:table-and-caption|fo:table-caption|fo:table">
+ <xsl:call-template name="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>
+
+ <!-- Formatting Objects for Lists -->
+ <xsl:template match="fo:list-block|fo:list-item|fo:list-item-label|fo:list-item-body">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Dynamic Effects: Link and Multi Formatting Objects -->
+ <xsl:template match="fo:basic-link">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Out-of-Line Formatting Objects -->
+ <xsl:template match="fo:float|fo:footnote|fo:footnote-body">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+ <!-- Other Formatting Objects -->
+ <xsl:template match="fo:wrapper|fo:marker">
+ <xsl:call-template name="copy"/>
+ </xsl:template>
+
+
+ <!-- Discard descendants of fo:leader -->
+ <xsl:template match="fo:leader"/>
+
+
+ <!-- Keep fox:alt-text and role attributes, discard everything else -->
+ <xsl:template match="@fox:alt-text|@role">
+ <xsl:copy-of select="."/>
+ </xsl:template>
+
+ <xsl:template match="@*"/>
+
+
+ <!-- Discard text -->
+ <xsl:template match="text()"/>
+
+</xsl:stylesheet>
+++ /dev/null
-<?xml version="1.0" standalone="no"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- $Id$ -->
-<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
- xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
-
- <fo:layout-master-set>
- <fo:simple-page-master master-name="page"
- page-height="400pt" page-width="300pt" margin="20pt" margin-top="10pt">
- <fo:region-body margin-top="20pt"/>
- <fo:region-before extent="15pt"/>
- </fo:simple-page-master>
- </fo:layout-master-set>
-
- <fo:page-sequence master-reference="page">
- <fo:static-content flow-name="xsl-region-before">
- <fo:block id="1" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
- border-bottom="0.25pt solid black">This is the page header<fo:leader/>Page <fo:page-number
- id="2"/></fo:block>
- </fo:static-content>
- <fo:static-content flow-name="xsl-footnote-separator">
- <fo:block id="3"><fo:leader leader-length="100pt" leader-pattern="rule"/></fo:block>
- </fo:static-content>
- <fo:flow flow-name="xsl-region-body">
- <fo:block id="4">This is a link to the <fo:wrapper id="5" color="blue"><fo:basic-link id="6"
- internal-destination="second-start">next page-sequence</fo:basic-link></fo:wrapper>
- (which starts on page <fo:page-number-citation id="7" ref-id="second-start"/> and ends on
- page <fo:page-number-citation-last id="8" ref-id="second-end"/>).</fo:block>
- <fo:block id="9" font-family="sans-serif" font-weight="bold" space-before="1em"
- space-after="0.2em" role="H1"><fo:block id="10">A Title Block</fo:block></fo:block>
- <fo:block id="11">This block of text contains a footnote<fo:footnote id="12"><fo:inline id="13"
- baseline-shift="super" font-size="70%">1</fo:inline><fo:footnote-body id="14"><fo:block
- id="15">A footnote with a link to the <fo:wrapper id="16" color="blue"><fo:basic-link
- id="17" external-destination="http://xmlgraphics.apache.org/fop/">FOP
- website</fo:basic-link></fo:wrapper></fo:block></fo:footnote-body></fo:footnote>
- call.</fo:block>
- <fo:table id="18" space-before="1em" width="100%" table-layout="fixed">
- <fo:table-column id="19" column-width="proportional-column-width(1)"/>
- <fo:table-column id="20" column-width="proportional-column-width(2)"/>
- <fo:table-header id="21">
- <fo:table-row id="22">
- <fo:table-cell id="23" border="2pt solid black" padding="2pt 2pt 0">
- <fo:block id="24">Header 1.1</fo:block>
- </fo:table-cell>
- <fo:table-cell id="25" border="2pt solid black" padding="2pt 2pt 0">
- <fo:block id="26">Header 1.2</fo:block>
- </fo:table-cell>
- </fo:table-row>
- </fo:table-header>
- <fo:table-footer id="27">
- <fo:table-row id="28">
- <fo:table-cell id="29" border="2pt solid black" padding="2pt 2pt 0">
- <fo:block id="30">Footer 1.1</fo:block>
- </fo:table-cell>
- <fo:table-cell id="31" border="2pt solid black" padding="2pt 2pt 0">
- <fo:block id="32">Footer 1.2</fo:block>
- </fo:table-cell>
- </fo:table-row>
- </fo:table-footer>
- <fo:table-body id="33">
- <fo:table-row id="34">
- <fo:table-cell id="35" border="1pt solid black" padding="2pt 2pt 0">
- <fo:block id="36">Cell 1.1</fo:block>
- </fo:table-cell>
- <fo:table-cell id="37" border="1pt solid black" padding="2pt 2pt 0">
- <fo:block id="38">Cell 1.2</fo:block>
- </fo:table-cell>
- </fo:table-row>
- <fo:table-row id="39">
- <fo:table-cell id="40" border="1pt solid black" padding="2pt 2pt 0">
- <fo:block id="41">Cell 2.1</fo:block>
- </fo:table-cell>
- <fo:table-cell id="42" border="1pt solid black" padding="2pt 2pt 0">
- <fo:block id="43">Cell 2.2</fo:block>
- </fo:table-cell>
- </fo:table-row>
- </fo:table-body>
- </fo:table>
- <fo:block-container id="44" space-before="1.2em">
- <fo:block-container id="45" absolute-position="absolute" top="6pt" right="2.5pt"
- inline-progression-dimension="37%" padding="3pt 1pt 2pt 3pt" border="1.5pt solid
- darkblue">
- <fo:block id="46" color="darkblue" font-size="80%">This is an absolutely positioned
- block-container. Nullam interdum mattis ipsum sit amet molestie.</fo:block>
- </fo:block-container>
- <fo:block id="47" end-indent="37% + 15pt">Lorem ipsum dolor sit amet, consectetur adipiscing
- elit. Integer vel lacinia diam. Etiam venenatis magna vel libero imperdiet
- rhoncus.</fo:block>
- </fo:block-container>
- </fo:flow>
- </fo:page-sequence>
-
- <fo:page-sequence master-reference="page">
- <fo:static-content id="48" flow-name="xsl-region-before">
- <fo:block id="49" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
- border-bottom="0.25pt solid black">This is the page header<fo:leader id="50"/>Page
- <fo:page-number id="51"/></fo:block>
- </fo:static-content>
- <fo:flow flow-name="xsl-region-body" text-align="justify" space-before.minimum="8pt"
- space-before.optimum="10pt" space-before.maximum="12pt">
- <fo:block id="second-start">Starting a new page-sequence.</fo:block>
- <fo:block id="52" text-align="center">The <fo:external-graphic id="53"
- src="test/resources/images/fop-logo-color-24bit.png"
- inline-progression-dimension.maximum="50%" content-width="scale-to-fit"
- alignment-adjust="-46%" alignment-baseline="middle" fox:alt-text="FOP Logo"/>
- logo.</fo:block>
- <fo:list-block id="54" provisional-distance-between-starts="15pt"
- provisional-label-separation="0" space-before="inherit">
- <fo:list-item id="55">
- <fo:list-item-label id="56" end-indent="label-end()">
- <fo:block id="57">1.</fo:block>
- </fo:list-item-label>
- <fo:list-item-body id="58" start-indent="body-start()">
- <fo:block id="59">First item of a list</fo:block>
- </fo:list-item-body>
- </fo:list-item>
- <fo:list-item id="60">
- <fo:list-item-label id="61" end-indent="label-end()">
- <fo:block id="62">2.</fo:block>
- </fo:list-item-label>
- <fo:list-item-body id="63" start-indent="body-start()">
- <fo:block id="64">Second item of a list</fo:block>
- </fo:list-item-body>
- </fo:list-item>
- <fo:list-item id="65">
- <fo:list-item-label id="66" end-indent="label-end()">
- <fo:block id="67">3.</fo:block>
- </fo:list-item-label>
- <fo:list-item-body id="68" start-indent="body-start()">
- <fo:block id="69">Third item of a list</fo:block>
- </fo:list-item-body>
- </fo:list-item>
- </fo:list-block>
- <fo:block id="70" text-align="center"><fo:instream-foreign-object id="71"
- inline-progression-dimension.maximum="50%" content-width="scale-to-fit">
- <svg xmlns="http://www.w3.org/2000/svg" width="319" height="286.6">
- <g style="fill-opacity:0.7; stroke:black; stroke-width:3"
- transform="translate(0, 286.6) scale(1, -1) translate(100, 100)">
- <circle cx="50" cy="86.6" r="80" style="fill:red;"/>
- <circle cx="0" cy="0" r="80" style="fill:green;"/>
- <circle cx="100" cy="0" r="80" style="fill:blue;"/>
- </g>
- </svg>
- </fo:instream-foreign-object></fo:block>
- <fo:block id="72" space-before="inherit">A block containing an <fo:inline id="73"
- border="0.5pt solid black" padding="2pt" padding-bottom="0">inline</fo:inline>
- element.</fo:block>
- <fo:block id="74" space-before="inherit">A block containing a fancy <fo:character id="75"
- border="1pt solid black" padding="0 2pt 1pt 2pt" font-family="Symbol" character="♦"/>
- character.</fo:block>
- <fo:block id="76" space-before="inherit" text-align-last="justify">A leader with special
- content: <fo:leader id="77" leader-pattern="use-content"><fo:inline id="78"><fo:character
- id="79" character=" "/><fo:inline id="80" border="0.5pt solid black"
- padding-left="2pt" padding-right="2pt"><fo:character id="81" baseline-shift="-10%"
- character="•"/></fo:inline></fo:inline></fo:leader>.</fo:block>
- <fo:block id="second-end" space-before="inherit">Ending the page-sequence.</fo:block>
- </fo:flow>
- </fo:page-sequence>
-
-</fo:root>
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.Root;
import org.apache.fop.fo.pagination.StaticContent;
/**
@Override
public void startDocument() throws SAXException {
- actualEvents.add("start root");
+ actualEvents.add("start document");
}
@Override
public void endDocument() throws SAXException {
- actualEvents.add("end root");
+ actualEvents.add("end document");
+ }
+
+ @Override
+ public void startRoot(Root root) {
+ startElement(root);
+ }
+
+ @Override
+ public void endRoot(Root root) {
+ endElement(root);
}
@Override
}
private void loadDocument() {
- Class<?> clazz = getClass();
- String documentName = clazz.getSimpleName() + ".fo";
- document = clazz.getResourceAsStream(documentName);
+ document = getClass().getResourceAsStream("complete_document.fo");
}
private void loadExpectedEvents() throws IOException {
* @throws LoadingException if an error occurs when parsing the document
*/
public void parse(InputStream document) throws FOPException, LoadingException {
- FOUserAgent foUserAgent = createFOUserAgent();
+ parse(document, createFOUserAgent());
+ }
+
+ /**
+ * Runs FOP on the given document with the supplied {@link FOUserAgent}.
+ *
+ * @param document XSL-FO document to parse
+ * @param foUserAgent The user agent
+ * @throws FOPException if an error occurs when initializing FOP
+ * @throws LoadingException if an error occurs when parsing the document
+ */
+ public void parse(InputStream document, FOUserAgent foUserAgent)
+ throws FOPException, LoadingException {
fop = FOP_FACTORY.newFop(foUserAgent);
createTransformer();
runTransformer(document);
}
- private FOUserAgent createFOUserAgent() {
+ /**
+ * Creates a new {@link FOUserAgent}.
+ * @return It
+ */
+ public FOUserAgent createFOUserAgent() {
FOUserAgent userAgent = FOP_FACTORY.newFOUserAgent();
FOEventHandler foEventHandler = foEventHandlerFactory.newFOEventHandler(userAgent);
userAgent.setFOEventHandlerOverride(foEventHandler);
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
+ xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="page"
+ page-height="400pt" page-width="300pt" margin="20pt" margin-top="10pt">
+ <fo:region-body margin-top="20pt"/>
+ <fo:region-before extent="15pt"/>
+ </fo:simple-page-master>
+ </fo:layout-master-set>
+
+ <fo:page-sequence master-reference="page">
+ <fo:static-content flow-name="xsl-region-before">
+ <fo:block id="1" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
+ border-bottom="0.25pt solid black">This is the page header<fo:leader/>Page <fo:page-number
+ id="2"/></fo:block>
+ </fo:static-content>
+ <fo:static-content flow-name="xsl-footnote-separator">
+ <fo:block id="3"><fo:leader leader-length="100pt" leader-pattern="rule"/></fo:block>
+ </fo:static-content>
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block id="4">This is a link to the <fo:wrapper id="5" color="blue"><fo:basic-link id="6"
+ internal-destination="second-start">next page-sequence</fo:basic-link></fo:wrapper>
+ (which starts on page <fo:page-number-citation id="7" ref-id="second-start"/> and ends on
+ page <fo:page-number-citation-last id="8" ref-id="second-end"/>).</fo:block>
+ <fo:block id="9" font-family="sans-serif" font-weight="bold" space-before="1em"
+ space-after="0.2em" role="H1"><fo:block id="10">A Title Block</fo:block></fo:block>
+ <fo:block id="11">This block of text contains a footnote<fo:footnote id="12"><fo:inline id="13"
+ baseline-shift="super" font-size="70%">1</fo:inline><fo:footnote-body id="14"><fo:block
+ id="15">A footnote with a link to the <fo:wrapper id="16" color="blue"><fo:basic-link
+ id="17" external-destination="http://xmlgraphics.apache.org/fop/">FOP
+ website</fo:basic-link></fo:wrapper></fo:block></fo:footnote-body></fo:footnote>
+ call.</fo:block>
+ <fo:table id="18" space-before="1em" width="100%" table-layout="fixed">
+ <fo:table-column id="19" column-width="proportional-column-width(1)"/>
+ <fo:table-column id="20" column-width="proportional-column-width(2)"/>
+ <fo:table-header id="21">
+ <fo:table-row id="22">
+ <fo:table-cell id="23" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="24">Header 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="25" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="26">Header 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-header>
+ <fo:table-footer id="27">
+ <fo:table-row id="28">
+ <fo:table-cell id="29" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="30">Footer 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="31" border="2pt solid black" padding="2pt 2pt 0">
+ <fo:block id="32">Footer 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-footer>
+ <fo:table-body id="33">
+ <fo:table-row id="34">
+ <fo:table-cell id="35" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="36">Cell 1.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="37" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="38">Cell 1.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ <fo:table-row id="39">
+ <fo:table-cell id="40" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="41">Cell 2.1</fo:block>
+ </fo:table-cell>
+ <fo:table-cell id="42" border="1pt solid black" padding="2pt 2pt 0">
+ <fo:block id="43">Cell 2.2</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block-container id="44" space-before="1.2em">
+ <fo:block-container id="45" absolute-position="absolute" top="6pt" right="2.5pt"
+ inline-progression-dimension="37%" padding="3pt 1pt 2pt 3pt" border="1.5pt solid
+ darkblue">
+ <fo:block id="46" color="darkblue" font-size="80%">This is an absolutely positioned
+ block-container. Nullam interdum mattis ipsum sit amet molestie.</fo:block>
+ </fo:block-container>
+ <fo:block id="47" end-indent="37% + 15pt">Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Integer vel lacinia diam. Etiam venenatis magna vel libero imperdiet
+ rhoncus.</fo:block>
+ </fo:block-container>
+ </fo:flow>
+ </fo:page-sequence>
+
+ <fo:page-sequence master-reference="page">
+ <fo:static-content id="48" flow-name="xsl-region-before">
+ <fo:block id="49" font-size="7pt" text-align-last="justify" padding-bottom="2pt"
+ border-bottom="0.25pt solid black">This is the page header<fo:leader id="50"/>Page
+ <fo:page-number id="51"/></fo:block>
+ </fo:static-content>
+ <fo:flow flow-name="xsl-region-body" text-align="justify" space-before.minimum="8pt"
+ space-before.optimum="10pt" space-before.maximum="12pt">
+ <fo:block id="second-start">Starting a new page-sequence.</fo:block>
+ <fo:block id="52" text-align="center">The <fo:external-graphic id="53"
+ src="test/resources/images/fop-logo-color-24bit.png"
+ inline-progression-dimension.maximum="50%" content-width="scale-to-fit"
+ alignment-adjust="-46%" alignment-baseline="middle" fox:alt-text="FOP Logo"/>
+ logo.</fo:block>
+ <fo:list-block id="54" provisional-distance-between-starts="15pt"
+ provisional-label-separation="0" space-before="inherit">
+ <fo:list-item id="55">
+ <fo:list-item-label id="56" end-indent="label-end()">
+ <fo:block id="57">1.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="58" start-indent="body-start()">
+ <fo:block id="59">First item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item id="60">
+ <fo:list-item-label id="61" end-indent="label-end()">
+ <fo:block id="62">2.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="63" start-indent="body-start()">
+ <fo:block id="64">Second item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item id="65">
+ <fo:list-item-label id="66" end-indent="label-end()">
+ <fo:block id="67">3.</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body id="68" start-indent="body-start()">
+ <fo:block id="69">Third item of a list</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </fo:list-block>
+ <fo:block id="70" text-align="center"><fo:instream-foreign-object id="71"
+ inline-progression-dimension.maximum="50%" content-width="scale-to-fit"
+ fox:alt-text="An inline SVG">
+ <svg xmlns="http://www.w3.org/2000/svg" width="319" height="286.6">
+ <g style="fill-opacity:0.7; stroke:black; stroke-width:3"
+ transform="translate(0, 286.6) scale(1, -1) translate(100, 100)">
+ <circle cx="50" cy="86.6" r="80" style="fill:red;"/>
+ <circle cx="0" cy="0" r="80" style="fill:green;"/>
+ <circle cx="100" cy="0" r="80" style="fill:blue;"/>
+ </g>
+ </svg>
+ </fo:instream-foreign-object></fo:block>
+ <fo:block id="72" space-before="inherit">A block containing an <fo:inline id="73"
+ border="0.5pt solid black" padding="2pt" padding-bottom="0">inline</fo:inline>
+ element.</fo:block>
+ <fo:block id="74" space-before="inherit">A block containing a fancy <fo:character id="75"
+ border="1pt solid black" padding="0 2pt 1pt 2pt" font-family="Symbol" character="♦"/>
+ character.</fo:block>
+ <fo:block id="76" space-before="inherit" text-align-last="justify">A leader with special
+ content: <fo:leader id="77" leader-pattern="use-content"><fo:inline id="78"><fo:character
+ id="79" character=" "/><fo:inline id="80" border="0.5pt solid black"
+ padding-left="2pt" padding-right="2pt"><fo:character id="81" baseline-shift="-10%"
+ character="•"/></fo:inline></fo:inline></fo:leader>.</fo:block>
+ <fo:block id="second-end" space-before="inherit">Ending the page-sequence.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+
+</fo:root>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
- <xsl:template match="fo:root">
+ <xsl:template match="/">
<event>
- <xsl:text>start root</xsl:text>
+ <xsl:text>start document</xsl:text>
</event>
- <xsl:apply-templates select="fo:page-sequence"/>
+ <xsl:apply-templates/>
<event>
- <xsl:text>end root</xsl:text>
+ <xsl:text>end document</xsl:text>
</event>
</xsl:template>
+ <xsl:template match="fo:root">
+ <event>start root</event>
+ <xsl:apply-templates select="fo:page-sequence"/>
+ <event>end root</event>
+ </xsl:template>
+
<xsl:template match="fo:*">
<xsl:call-template name="process.node">
<xsl:with-param name="id">
import org.apache.fop.fo.FONodeMocks;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.flow.table.UnimplementedWarningNeutralizer;
/**
* This tests that all the FONodes that implement CommonAccessibilityHolder correctly configure
static {
/* This triggers 'unimplemented feature' FO validation events so that the event system is
* not triggered when testing, avoiding extra convoluted dependency stubbing. */
-// UnimplementedWarningNeutralizer.neutralizeUnimplementedWarning();
+ UnimplementedWarningNeutralizer.neutralizeUnimplementedWarning();
IMPLEMENTATIONS.add(org.apache.fop.fo.flow.BasicLink.class);
IMPLEMENTATIONS.add(org.apache.fop.fo.flow.Block.class);
@RunWith(Parameterized.class)
public class IFParserTestCase extends AbstractIFTestCase {
+ /** Set this to true to get the correspondence between test number and test file. */
+ private static final boolean DEBUG = false;
+
/**
* Gets the parameters for this test
*
*/
@Parameters
public static Collection<File[]> getParameters() throws IOException {
- return LayoutEngineTestUtils.getLayoutTestFiles();
+ Collection<File[]> testFiles = LayoutEngineTestUtils.getLayoutTestFiles();
+ if (DEBUG) {
+ printFiles(testFiles);
+ }
+ return testFiles;
+ }
+
+ private static void printFiles(Collection<File[]> files) {
+ int index = 0;
+ for (File[] file : files) {
+ assert file.length == 1;
+ System.out.println(String.format("%3d %s", index++, file[0]));
+ }
}
/**
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.InOrder;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.fo.FOElementMapping;
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fo.extensions.InternalElementMapping;
+import org.apache.fop.util.XMLUtil;
+
+public class IFStructureTreeBuilderTestCase {
+
+ private IFStructureTreeBuilder sut;
+
+ @Before
+ public void setUp() {
+ sut = new IFStructureTreeBuilder();
+ }
+
+ @Test
+ public void startAndEndPageSequence() throws SAXException {
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ try {
+ sut.replayEventsForPageSequence(handler, 0);
+ fail("No page sequences created");
+ } catch (IndexOutOfBoundsException e) {
+ // Expected
+ }
+
+ sut.startPageSequence(null);
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ InOrder inOrder = inOrder(handler);
+
+ inOrder.verify(handler).startPrefixMapping(
+ InternalElementMapping.STANDARD_PREFIX, InternalElementMapping.URI);
+ inOrder.verify(handler).startPrefixMapping(
+ ExtensionElementMapping.STANDARD_PREFIX, ExtensionElementMapping.URI);
+ inOrder.verify(handler).startElement(eq(IFConstants.NAMESPACE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ any(Attributes.class));
+ inOrder.verify(handler).endElement(eq(IFConstants.NAMESPACE),
+ eq(IFConstants.EL_STRUCTURE_TREE),
+ eq(IFConstants.EL_STRUCTURE_TREE));
+ inOrder.verify(handler).endPrefixMapping(ExtensionElementMapping.STANDARD_PREFIX);
+ inOrder.verify(handler).endPrefixMapping(InternalElementMapping.STANDARD_PREFIX);
+ }
+
+ @Test
+ public void startNode() throws Exception {
+ final String[] attributes = {"ptr", "1"};
+ final String nodeName = "block";
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ sut.startPageSequence(null);
+ sut.startNode(nodeName, createSimpleAttributes(attributes));
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ verify(handler).startElement(eq(FOElementMapping.URI), eq(nodeName),
+ eq(FOElementMapping.STANDARD_PREFIX + ":" + nodeName),
+ AttributesMatcher.match(createSimpleAttributes(attributes)));
+ }
+
+ @Test
+ public void endNode() throws Exception {
+ final String nodeName = "block";
+ final ContentHandler handler = mock(ContentHandler.class);
+
+ sut.startPageSequence(null);
+ sut.endNode(nodeName);
+ sut.endPageSequence();
+
+ sut.replayEventsForPageSequence(handler, 0);
+
+ verify(handler).endElement(eq(FOElementMapping.URI), eq(nodeName),
+ eq(FOElementMapping.STANDARD_PREFIX + ":" + nodeName));
+ }
+
+ private static Attributes createSimpleAttributes(String... attributes) {
+ assert (attributes.length % 2 == 0);
+ final AttributesImpl atts = new AttributesImpl();
+ for (int i = 0; i < attributes.length; i += 2) {
+ String key = attributes[i];
+ String value = attributes[i + 1];
+ atts.addAttribute("", key, key, XMLUtil.CDATA, value);
+ }
+ return atts;
+ }
+
+ private static final class AttributesMatcher extends ArgumentMatcher<Attributes> {
+
+ private final Attributes expected;
+
+ private AttributesMatcher(Attributes expected) {
+ this.expected = expected;
+ }
+
+ public static Attributes match(Attributes expected) {
+ return argThat(new AttributesMatcher(expected));
+ }
+
+ public boolean matches(Object attributes) {
+ return attributesEqual(expected, (Attributes) attributes);
+ }
+
+ private static boolean attributesEqual(Attributes attributes1, Attributes attributes2) {
+ if (attributes1.getLength() != attributes2.getLength()) {
+ return false;
+ }
+ for (int i = 0; i < attributes1.getLength(); i++) {
+ if (attributes1.getLocalName(i) != attributes2.getLocalName(i)) {
+ return false;
+ }
+ if (attributes1.getQName(i) != attributes2.getQName(i)) {
+ return false;
+ }
+ if (attributes1.getType(i) != attributes2.getType(i)) {
+ return false;
+ }
+ if (attributes1.getURI(i) != attributes2.getURI(i)) {
+ return false;
+ }
+ if (attributes1.getValue(i) != attributes2.getValue(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import org.apache.fop.render.intermediate.IFStructureTreeBuilder.SAXEventRecorder;
+import org.apache.fop.util.XMLUtil;
+
+/**
+ * Tests {@link SAXEventRecorder}.
+ */
+public class SAXEventRecorderTestCase {
+
+ private static final String URI = "http://www.example.com/";
+
+ private SAXEventRecorder sut;
+
+ @Before
+ public void setUp() {
+ sut = new SAXEventRecorder();
+ }
+
+ @Test
+ public void testStartEvent() throws SAXException {
+ final String localName = "element";
+ final String qName = "prefix:" + localName;
+ final Attributes attributes = new AttributesImpl();
+
+ sut.startElement(URI, localName, qName, attributes);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).startElement(URI, localName, qName, attributes);
+ }
+
+ @Test
+ public void testEndEvent() throws SAXException {
+ final String localName = "element";
+ final String qName = "prefix:" + localName;
+ sut.endElement(URI, localName, qName);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).endElement(URI, localName, qName);
+ }
+
+ @Test
+ public void testStartPrefixMapping() throws SAXException {
+ final String prefix = "prefix";
+
+ sut.startPrefixMapping(URI, prefix);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).startPrefixMapping(URI, prefix);
+ }
+
+ @Test
+ public void testEndPrefixMapping() throws SAXException {
+ final String prefix = "prefix";
+
+ sut.endPrefixMapping(prefix);
+ ContentHandler handler = mock(ContentHandler.class);
+ sut.replay(handler);
+ verify(handler).endPrefixMapping(prefix);
+ }
+
+ @Test
+ public void completeTest() throws SAXException {
+ final String localName1 = "element";
+ final String qName1 = "prefix:" + localName1;
+ final Attributes attributes1 = createAttributes(URI, localName1, qName1, "value-1");
+ final String localName2 = "element2";
+ final String qName2 = "prefix:" + localName2;
+ final Attributes attributes2 = createAttributes(URI, localName2, qName2, "value-2");
+ final ContentHandler handler = mock(ContentHandler.class);
+ final String extensionUrl = "http://www.example.com/extension";
+ final String extensionPrefix = "ext";
+
+ sut.startPrefixMapping(extensionPrefix, extensionUrl);
+ sut.startElement(URI, localName1, qName1, attributes1);
+ sut.startElement(URI, localName2, qName2, attributes2);
+ sut.endElement(URI, localName2, qName2);
+ sut.endElement(URI, localName1, qName1);
+ sut.endPrefixMapping(extensionPrefix);
+
+ sut.replay(handler);
+
+ InOrder inOrder = inOrder(handler);
+ inOrder.verify(handler).startPrefixMapping(extensionPrefix, extensionUrl);
+ inOrder.verify(handler).startElement(URI, localName1, qName1, attributes1);
+ inOrder.verify(handler).startElement(URI, localName2, qName2, attributes2);
+ inOrder.verify(handler).endElement(URI, localName2, qName2);
+ inOrder.verify(handler).endElement(URI, localName1, qName1);
+ inOrder.verify(handler).endPrefixMapping(extensionPrefix);
+ }
+
+ private static Attributes createAttributes(String uri, String localName,
+ String qName, String value) {
+ final AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute(uri, localName, qName, XMLUtil.CDATA, value);
+ return atts;
+ }
+
+}
--- /dev/null
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Locale;
+
+import org.junit.Test;
+
+/**
+ * Tests {@link LanguageTags}.
+ */
+public class LanguageTagsTestCase {
+
+ @Test(expected = NullPointerException.class)
+ public void toLanguageTagRejectsNull() {
+ LanguageTags.toLanguageTag(null);
+ }
+
+ @Test
+ public void testToLanguageTag() throws Exception {
+ assertEquals("", LanguageTags.toLanguageTag(new Locale("")));
+ assertEquals("en", LanguageTags.toLanguageTag(new Locale("en")));
+ assertEquals("en-US", LanguageTags.toLanguageTag(new Locale("en", "US")));
+ assertEquals("en-US", LanguageTags.toLanguageTag(new Locale("EN", "us")));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void toLocaleRejectsNull() {
+ LanguageTags.toLocale(null);
+ }
+
+ @Test
+ public void testRFC3066ToLocale() throws Exception {
+ assertEquals(new Locale(""), LanguageTags.toLocale(""));
+ assertEquals(new Locale("en"), LanguageTags.toLocale("en"));
+ assertEquals(new Locale("en", "US"), LanguageTags.toLocale("en-US"));
+ assertEquals(new Locale("en", "US"), LanguageTags.toLocale("EN-us"));
+ }
+}
+++ /dev/null
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import java.util.Locale;
-
-import org.junit.Test;
-
-/**
- * Tests {@link XMLUtil}.
- */
-public class XMLUtilTestCase {
-
- @Test
- public void testLocaleToRFC3066() throws Exception {
- assertNull(XMLUtil.toRFC3066(null));
- assertEquals("en", XMLUtil.toRFC3066(new Locale("en")));
- assertEquals("en-US", XMLUtil.toRFC3066(new Locale("en", "US")));
- assertEquals("en-US", XMLUtil.toRFC3066(new Locale("EN", "us")));
- }
-
- @Test
- public void testRFC3066ToLocale() throws Exception {
- assertNull(XMLUtil.convertRFC3066ToLocale(null));
- assertNull(XMLUtil.convertRFC3066ToLocale(""));
- assertEquals(new Locale("en"), XMLUtil.convertRFC3066ToLocale("en"));
- assertEquals(new Locale("en", "US"), XMLUtil.convertRFC3066ToLocale("en-US"));
- assertEquals(new Locale("en", "US"), XMLUtil.convertRFC3066ToLocale("EN-us"));
- }
-}