git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@819585 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -0,0 +1,95 @@ | |||
/* | |||
* 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.ArrayList; | |||
import java.util.List; | |||
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.w3c.dom.NodeList; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.apache.fop.util.DelegatingContentHandler; | |||
/** | |||
* A StructureTree implementation re-created from the structure stored in an IF | |||
* XML document. | |||
*/ | |||
public class ParsedStructureTree implements StructureTree { | |||
private SAXTransformerFactory factory; | |||
private List pageSequenceStructures = new ArrayList(); | |||
/** | |||
* Creates a new instance. | |||
* | |||
* @param factory a factory internally used to build the structures of page | |||
* sequences | |||
*/ | |||
public ParsedStructureTree(SAXTransformerFactory factory) { | |||
this.factory = factory; | |||
} | |||
/** | |||
* 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. | |||
* This class will automatically number the structure trees. | |||
* | |||
* @return a handler for parsing the <structure-tree> 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 not text node in the structure tree. This is just | |||
* whitespace => ignore | |||
*/ | |||
} | |||
public void endDocument() throws SAXException { | |||
super.endDocument(); | |||
pageSequenceStructures.add(domResult.getNode().getFirstChild().getChildNodes()); | |||
} | |||
}; | |||
} | |||
/** {@inheritDoc} */ | |||
public NodeList getPageSequence(int number) { | |||
return (NodeList) pageSequenceStructures.get(number - 1); | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
/* | |||
* 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.Iterator; | |||
import javax.xml.namespace.NamespaceContext; | |||
import javax.xml.transform.Transformer; | |||
import javax.xml.transform.TransformerFactory; | |||
import javax.xml.transform.dom.DOMSource; | |||
import javax.xml.transform.stream.StreamResult; | |||
import javax.xml.xpath.XPath; | |||
import javax.xml.xpath.XPathConstants; | |||
import javax.xml.xpath.XPathExpressionException; | |||
import javax.xml.xpath.XPathFactory; | |||
import org.w3c.dom.Node; | |||
import org.w3c.dom.NodeList; | |||
/** | |||
* A StructureTree implementation created from the reduced FO tree, in the form | |||
* of a single DOM document obtained by XSL Transformation of the original FO | |||
* tree. | |||
*/ | |||
final class SimpleStructureTree implements StructureTree { | |||
private final Node reducedFOTree; | |||
private static class NamespaceContextImpl implements NamespaceContext { | |||
private String uri; | |||
private String prefix; | |||
public NamespaceContextImpl() { | |||
} | |||
public NamespaceContextImpl(String prefix, String uri) { | |||
this.uri = uri; | |||
this.prefix = prefix; | |||
} | |||
public String getNamespaceURI(String prefix) { | |||
return uri; | |||
} | |||
public void setNamespaceURI(String uri) { | |||
this.uri = uri; | |||
} | |||
public String getPrefix(String uri) { | |||
return prefix; | |||
} | |||
public void setPrefix(String prefix) { | |||
this.prefix = prefix; | |||
} | |||
public Iterator getPrefixes(String uri) { | |||
return null; | |||
} | |||
} | |||
SimpleStructureTree(Node reducedFOTree) { | |||
this.reducedFOTree = reducedFOTree; | |||
} | |||
/** {@inheritDoc} */ | |||
public NodeList getPageSequence(int number) { | |||
XPath xpath = XPathFactory.newInstance().newXPath(); | |||
NamespaceContext namespaceContext = new NamespaceContextImpl("fo", | |||
"http://www.w3.org/1999/XSL/Format"); | |||
xpath.setNamespaceContext(namespaceContext); | |||
String xpathExpr = "/fo:root/fo:page-sequence[" + Integer.toString(number) + "]/*"; | |||
try { | |||
return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET); | |||
} catch (XPathExpressionException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public String toString() { | |||
try { | |||
Transformer t = TransformerFactory.newInstance().newTransformer(); | |||
Writer str = new StringWriter(); | |||
t.transform(new DOMSource(reducedFOTree), new StreamResult(str)); | |||
return str.toString(); | |||
} catch (Exception e) { | |||
return e.toString(); | |||
} | |||
} | |||
} |
@@ -19,62 +19,13 @@ | |||
package org.apache.fop.accessibility; | |||
import java.util.Iterator; | |||
import javax.xml.namespace.NamespaceContext; | |||
import javax.xml.xpath.XPath; | |||
import javax.xml.xpath.XPathConstants; | |||
import javax.xml.xpath.XPathExpressionException; | |||
import javax.xml.xpath.XPathFactory; | |||
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 Node reducedFOTree; | |||
private static class NamespaceContextImpl implements NamespaceContext { | |||
private String uri; | |||
private String prefix; | |||
public NamespaceContextImpl() { | |||
} | |||
public NamespaceContextImpl(String prefix, String uri) { | |||
this.uri = uri; | |||
this.prefix = prefix; | |||
} | |||
public String getNamespaceURI(String prefix) { | |||
return uri; | |||
} | |||
public void setNamespaceURI(String uri) { | |||
this.uri = uri; | |||
} | |||
public String getPrefix(String uri) { | |||
return prefix; | |||
} | |||
public void setPrefix(String prefix) { | |||
this.prefix = prefix; | |||
} | |||
public Iterator getPrefixes(String uri) { | |||
return null; | |||
} | |||
} | |||
StructureTree(Node reducedFOTree) { | |||
this.reducedFOTree = reducedFOTree; | |||
} | |||
public interface StructureTree { | |||
/** | |||
* Returns the list of nodes that are the children of the given page sequence. | |||
@@ -82,17 +33,6 @@ public final class StructureTree { | |||
* @param number number of the page sequence, 1-based | |||
* @return its children nodes | |||
*/ | |||
public NodeList getPageSequence(int number) { | |||
XPath xpath = XPathFactory.newInstance().newXPath(); | |||
NamespaceContext namespaceContext = new NamespaceContextImpl("fo", | |||
"http://www.w3.org/1999/XSL/Format"); | |||
xpath.setNamespaceContext(namespaceContext); | |||
String xpathExpr = "/fo:root/fo:page-sequence[" + Integer.toString(number) + "]/*"; | |||
NodeList getPageSequence(int number); | |||
try { | |||
return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET); | |||
} catch (XPathExpressionException e) { | |||
throw new RuntimeException(e); | |||
} | |||
} | |||
} |
@@ -78,7 +78,7 @@ class TransformerNodeEndProcessing extends TransformerNode { | |||
Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); | |||
DOMResult res = new DOMResult(); | |||
transformer.transform(src, res); | |||
userAgent.setStructureTree(new StructureTree(res.getNode())); | |||
userAgent.setStructureTree(new SimpleStructureTree(res.getNode())); | |||
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | |||
saxParserFactory.setNamespaceAware(true); |
@@ -33,20 +33,19 @@ import javax.xml.transform.TransformerException; | |||
import javax.xml.transform.sax.SAXResult; | |||
import javax.xml.transform.sax.SAXTransformerFactory; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.w3c.dom.DOMImplementation; | |||
import org.w3c.dom.Document; | |||
import org.xml.sax.Attributes; | |||
import org.xml.sax.ContentHandler; | |||
import org.xml.sax.SAXException; | |||
import org.xml.sax.helpers.AttributesImpl; | |||
import org.xml.sax.helpers.DefaultHandler; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.xmlgraphics.util.QName; | |||
import org.apache.fop.accessibility.ParsedStructureTree; | |||
import org.apache.fop.apps.FOUserAgent; | |||
import org.apache.fop.fo.ElementMapping; | |||
import org.apache.fop.fo.ElementMappingRegistry; | |||
@@ -60,6 +59,7 @@ import org.apache.fop.util.ContentHandlerFactory; | |||
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.XMLUtil; | |||
/** | |||
@@ -150,6 +150,26 @@ public class IFParser implements IFConstants { | |||
private ContentHandler navParser; | |||
private ParsedStructureTree structureTree; | |||
private ContentHandler structureTreeBuilder; | |||
private final class StructureTreeBuilder extends DelegatingContentHandler { | |||
private Attributes pageSequenceAttributes; | |||
private StructureTreeBuilder(Attributes pageSequenceAttributes, | |||
ParsedStructureTree structureTree) throws SAXException { | |||
super(structureTree.getHandlerForNextPageSequence()); | |||
this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes); | |||
} | |||
public void endDocument() throws SAXException { | |||
super.endDocument(); | |||
startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes); | |||
} | |||
} | |||
public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent, | |||
ElementMappingRegistry elementMappingRegistry) { | |||
this.documentHandler = documentHandler; | |||
@@ -173,6 +193,11 @@ public class IFParser implements IFConstants { | |||
elementHandlers.put(EL_LINE, new LineHandler()); | |||
elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler()); | |||
elementHandlers.put(EL_IMAGE, new ImageHandler()); | |||
if (userAgent.isAccessibilityEnabled()) { | |||
structureTree = new ParsedStructureTree(tFactory); | |||
userAgent.setStructureTree(structureTree); | |||
} | |||
} | |||
private void establishForeignAttributes(Map foreignAttributes) { | |||
@@ -200,19 +225,20 @@ public class IFParser implements IFConstants { | |||
} else { | |||
boolean handled = true; | |||
if (NAMESPACE.equals(uri)) { | |||
lastAttributes = new AttributesImpl(attributes); | |||
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName); | |||
content.setLength(0); | |||
ignoreCharacters = true; | |||
if (elementHandler != null) { | |||
ignoreCharacters = elementHandler.ignoreCharacters(); | |||
try { | |||
elementHandler.startElement(attributes); | |||
} catch (IFException ife) { | |||
handleIFException(ife); | |||
if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) { | |||
structureTreeBuilder = new StructureTreeBuilder(attributes, structureTree); | |||
} else if (localName.equals(EL_STRUCTURE_TREE)) { | |||
if (userAgent.isAccessibilityEnabled()) { | |||
delegate = structureTreeBuilder; | |||
} else { | |||
/* Delegate to a handler that does nothing */ | |||
delegate = new DefaultHandler(); | |||
} | |||
delegateDepth++; | |||
delegate.startDocument(); | |||
delegate.startElement(uri, localName, qName, attributes); | |||
} else { | |||
handled = false; | |||
handled = startIFElement(localName, attributes); | |||
} | |||
} else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) { | |||
if (this.navParser == null) { | |||
@@ -256,6 +282,25 @@ public class IFParser implements IFConstants { | |||
} | |||
} | |||
private boolean startIFElement(String localName, Attributes attributes) | |||
throws SAXException { | |||
lastAttributes = new AttributesImpl(attributes); | |||
ElementHandler elementHandler = (ElementHandler)elementHandlers.get(localName); | |||
content.setLength(0); | |||
ignoreCharacters = true; | |||
if (elementHandler != null) { | |||
ignoreCharacters = elementHandler.ignoreCharacters(); | |||
try { | |||
elementHandler.startElement(attributes); | |||
} catch (IFException ife) { | |||
handleIFException(ife); | |||
} | |||
return true; | |||
} else { | |||
return false; | |||
} | |||
} | |||
private void handleIFException(IFException ife) throws SAXException { | |||
if (ife.getCause() instanceof SAXException) { | |||
//unwrap |