From 223eb5df1f7597ac5269eb8dce45b6a7450144b8 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 19 Feb 2009 18:04:18 +0000 Subject: Bugzilla #46705: Accessibility and Tagged PDF Support Submitted by: Jost Klopfstein Changes to patch by jeremias: - Some style fixes - Various simplifications - Removal of dead code - Addressed some issues raised in Bugzilla (work in progress) - Fixed a couple of bugs on leader handling detected while testing (an NPE remains in leader_leader-pattern_use-content.xml) git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@745949 13f79535-47bb-0310-9956-ffa450edef68 --- .../services/org.apache.fop.fo.ElementMapping | 19 +- .../fop/accessibility/AccessibilityUtil.java | 89 +++++ .../apache/fop/accessibility/TransformerNode.java | 321 +++++++++++++++++ .../TransformerNodeEndProcessing.java | 115 ++++++ src/java/org/apache/fop/accessibility/addPtr.xsl | 30 ++ .../org/apache/fop/accessibility/reduceFOTree.xsl | 86 +++++ src/java/org/apache/fop/apps/FOUserAgent.java | 36 ++ src/java/org/apache/fop/apps/Fop.java | 7 +- src/java/org/apache/fop/apps/FopFactory.java | 14 + .../apache/fop/apps/FopFactoryConfigurator.java | 9 + src/java/org/apache/fop/area/Trait.java | 6 +- .../org/apache/fop/cli/CommandLineOptions.java | 3 + src/java/org/apache/fop/fo/Constants.java | 10 +- src/java/org/apache/fop/fo/FONode.java | 3 + src/java/org/apache/fop/fo/FOPropertyMapping.java | 12 + .../fop/fo/extensions/ExtensionElementMapping.java | 2 + .../apache/fop/fo/extensions/ExternalDocument.java | 2 +- .../fop/fo/extensions/InternalElementMapping.java | 85 +++++ .../org/apache/fop/fo/flow/AbstractGraphics.java | 7 + .../fop/fo/flow/AbstractPageNumberCitation.java | 7 + src/java/org/apache/fop/fo/flow/BasicLink.java | 6 + src/java/org/apache/fop/fo/flow/Block.java | 7 + src/java/org/apache/fop/fo/flow/Character.java | 7 + src/java/org/apache/fop/fo/flow/Inline.java | 7 + src/java/org/apache/fop/fo/flow/PageNumber.java | 7 + .../org/apache/fop/fo/flow/table/TableFObj.java | 7 + .../apache/fop/layoutmgr/BlockLayoutManager.java | 1 + src/java/org/apache/fop/layoutmgr/TraitSetter.java | 11 + .../inline/AbstractGraphicsLayoutManager.java | 1 + .../AbstractPageNumberCitationLayoutManager.java | 1 + .../layoutmgr/inline/BasicLinkLayoutManager.java | 1 + .../layoutmgr/inline/CharacterLayoutManager.java | 1 + .../layoutmgr/inline/PageNumberLayoutManager.java | 2 +- .../fop/layoutmgr/inline/TextLayoutManager.java | 20 +- src/java/org/apache/fop/pdf/PDFArray.java | 9 + src/java/org/apache/fop/pdf/PDFFactory.java | 42 ++- src/java/org/apache/fop/pdf/PDFLink.java | 12 + src/java/org/apache/fop/pdf/PDFPage.java | 17 + src/java/org/apache/fop/pdf/PDFParentTree.java | 50 +++ src/java/org/apache/fop/pdf/PDFRoot.java | 30 +- src/java/org/apache/fop/pdf/PDFStructElem.java | 196 ++++++++++ src/java/org/apache/fop/pdf/PDFStructTreeRoot.java | 67 ++++ src/java/org/apache/fop/pdf/PDFTextUtil.java | 52 ++- .../fop/render/AbstractPathOrientedRenderer.java | 6 +- .../org/apache/fop/render/AbstractRenderer.java | 12 +- src/java/org/apache/fop/render/afp/AFPPainter.java | 6 +- .../org/apache/fop/render/afp/AFPRenderer.java | 4 +- .../fop/render/intermediate/IFConstants.java | 2 + .../apache/fop/render/intermediate/IFPainter.java | 9 +- .../apache/fop/render/intermediate/IFParser.java | 8 +- .../apache/fop/render/intermediate/IFRenderer.java | 36 +- .../fop/render/intermediate/IFSerializer.java | 98 ++++- .../intermediate/extensions/AbstractAction.java | 19 +- .../apache/fop/render/java2d/Java2DPainter.java | 6 +- .../apache/fop/render/java2d/Java2DRenderer.java | 2 +- src/java/org/apache/fop/render/pcl/PCLPainter.java | 9 +- .../fop/render/pdf/PDFConfigurationConstants.java | 2 + .../apache/fop/render/pdf/PDFContentGenerator.java | 94 ++++- .../apache/fop/render/pdf/PDFDocumentHandler.java | 395 ++++++++++++++++++++- .../render/pdf/PDFDocumentNavigationHandler.java | 19 +- .../fop/render/pdf/PDFImageHandlerRawJPEG.java | 12 +- .../render/pdf/PDFImageHandlerRenderedImage.java | 8 +- .../apache/fop/render/pdf/PDFImageHandlerSVG.java | 15 +- src/java/org/apache/fop/render/pdf/PDFPainter.java | 132 ++++++- .../org/apache/fop/render/pdf/PDFRenderer.java | 5 +- .../apache/fop/render/pdf/PDFRenderingContext.java | 36 ++ .../apache/fop/render/pdf/PDFRenderingUtil.java | 21 ++ src/java/org/apache/fop/render/ps/PSPainter.java | 6 +- src/java/org/apache/fop/render/ps/PSRenderer.java | 4 +- .../org/apache/fop/render/txt/TXTRenderer.java | 2 +- src/java/org/apache/fop/util/DOM2SAX.java | 9 + 71 files changed, 2286 insertions(+), 108 deletions(-) create mode 100644 src/java/org/apache/fop/accessibility/AccessibilityUtil.java create mode 100644 src/java/org/apache/fop/accessibility/TransformerNode.java create mode 100644 src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java create mode 100644 src/java/org/apache/fop/accessibility/addPtr.xsl create mode 100644 src/java/org/apache/fop/accessibility/reduceFOTree.xsl create mode 100644 src/java/org/apache/fop/fo/extensions/InternalElementMapping.java create mode 100644 src/java/org/apache/fop/pdf/PDFParentTree.java create mode 100644 src/java/org/apache/fop/pdf/PDFStructElem.java create mode 100644 src/java/org/apache/fop/pdf/PDFStructTreeRoot.java (limited to 'src/java') diff --git a/src/java/META-INF/services/org.apache.fop.fo.ElementMapping b/src/java/META-INF/services/org.apache.fop.fo.ElementMapping index 0194b19db..09c79f5b7 100644 --- a/src/java/META-INF/services/org.apache.fop.fo.ElementMapping +++ b/src/java/META-INF/services/org.apache.fop.fo.ElementMapping @@ -1,10 +1,11 @@ -org.apache.fop.fo.FOElementMapping -org.apache.fop.fo.extensions.svg.SVGElementMapping -org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping -org.apache.fop.fo.extensions.ExtensionElementMapping -org.apache.fop.fo.extensions.OldExtensionElementMapping -org.apache.fop.fo.extensions.xmp.XMPElementMapping -org.apache.fop.fo.extensions.xmp.RDFElementMapping -org.apache.fop.render.ps.extensions.PSExtensionElementMapping -org.apache.fop.render.afp.extensions.AFPElementMapping +org.apache.fop.fo.FOElementMapping +org.apache.fop.fo.extensions.svg.SVGElementMapping +org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping +org.apache.fop.fo.extensions.ExtensionElementMapping +org.apache.fop.fo.extensions.InternalElementMapping +org.apache.fop.fo.extensions.OldExtensionElementMapping +org.apache.fop.fo.extensions.xmp.XMPElementMapping +org.apache.fop.fo.extensions.xmp.RDFElementMapping +org.apache.fop.render.ps.extensions.PSExtensionElementMapping +org.apache.fop.render.afp.extensions.AFPElementMapping org.apache.fop.render.pcl.extensions.PCLElementMapping \ No newline at end of file diff --git a/src/java/org/apache/fop/accessibility/AccessibilityUtil.java b/src/java/org/apache/fop/accessibility/AccessibilityUtil.java new file mode 100644 index 000000000..0dc5840b6 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/AccessibilityUtil.java @@ -0,0 +1,89 @@ +/* + * 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.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; + +/** + * Utility class for FOP's accessibility features. It provides the stylesheets used for processing + * the incoming XSL-FO stream and for setting up the transformation. + */ +public class AccessibilityUtil { + + private static SAXTransformerFactory tfactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + private static Templates addPtrTemplates; + private static Templates reduceFOTemplates; + + public static DefaultHandler decorateDefaultHandler(DefaultHandler handler, + FOUserAgent userAgent) throws FOPException { + DefaultHandler transformNode = new TransformerNodeEndProcessing( + getAddPtrTemplates(), handler, userAgent); + return transformNode; + } + + /** + * Returns the addPtr.xsl stylesheet. + * @return the addPtr.xsl stylesheet + * @throws FOPException if transform fails + */ + public static synchronized Templates getAddPtrTemplates() throws FOPException { + if (addPtrTemplates == null) { + //Load and cache stylesheet + Source src = new StreamSource( + AccessibilityUtil.class.getResource("addPtr.xsl").toExternalForm()); + try { + addPtrTemplates = tfactory.newTemplates(src); + } catch (TransformerConfigurationException e) { + throw new FOPException(e); + } + } + return addPtrTemplates; + } + + /** + * Returns the reduceFOTree.xsl stylesheet + * @return the reduceFOTree.xsl stylesheet + * @throws FOPException if an error occurs loading the stylesheet + */ + public static synchronized Templates getReduceFOTreeTemplates() throws FOPException { + if (reduceFOTemplates == null) { + //Load and cache stylesheet + Source src = new StreamSource( + AccessibilityUtil.class.getResource("reduceFOTree.xsl").toExternalForm()); + try { + reduceFOTemplates = tfactory.newTemplates(src); + } catch (TransformerConfigurationException e) { + throw new FOPException(e); + } + } + return reduceFOTemplates; + } + } \ No newline at end of file diff --git a/src/java/org/apache/fop/accessibility/TransformerNode.java b/src/java/org/apache/fop/accessibility/TransformerNode.java new file mode 100644 index 000000000..115c13703 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/TransformerNode.java @@ -0,0 +1,321 @@ +/* + * 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.File; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.fop.apps.FOPException; + +/** + * Used for accessibility to run required xslt transforms + */ +class TransformerNode extends DefaultHandler { + + private TransformerHandler transformerHandler; + + /** + * happens after setParams have been broadcast. + * + * @param downstreamHandler + * the handler passed in + * @param xsltFile + * for transform + * @throws FOPException + * for general errors + */ + public TransformerNode(DefaultHandler downstreamHandler, File xsltFile) throws FOPException { + try { + TransformerFactory transFact = TransformerFactory.newInstance(); + SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); + StreamSource ss = new StreamSource(xsltFile); + transformerHandler = saxTFactory.newTransformerHandler(ss); + SAXResult saxResult = new SAXResult(); + saxResult.setHandler(downstreamHandler); + transformerHandler.setResult(saxResult); + } catch (TransformerConfigurationException t) { + throw new FOPException(t); + } + } + + /** + * + * @param result + * of transform + * @param xsltFile + * for transform + * @throws FOPException + * for general errors + */ + public TransformerNode(Result result, File xsltFile) throws FOPException { + try { + TransformerFactory transFact = TransformerFactory.newInstance(); + SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); + StreamSource ss = new StreamSource(xsltFile); + transformerHandler = saxTFactory.newTransformerHandler(ss); + transformerHandler.setResult(result); + } catch (TransformerConfigurationException t) { + throw new FOPException(t); + } + } + + /** + * This is part of a two phase construction. Call this, then call + * initResult. + * + * @param xsltFile + * for transform + * @throws FOPException + * for general errors + */ + public TransformerNode(Source xsltFile) throws FOPException { + try { + TransformerFactory transFact = TransformerFactory.newInstance(); + SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); + transformerHandler = saxTFactory.newTransformerHandler(xsltFile); + } catch (TransformerConfigurationException t) { + throw new FOPException(t); + } + } + + /** + * This is part of a two phase construction. Call this, then call + * initResult. + * + * @param xsltTemplates + * for transform + * @throws FOPException + * for general errors + */ + public TransformerNode(Templates xsltTemplates) throws FOPException { + try { + TransformerFactory transFact = TransformerFactory.newInstance(); + SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); + transformerHandler = saxTFactory.newTransformerHandler(xsltTemplates); + } catch (TransformerConfigurationException t) { + throw new FOPException(t); + } + } + + /** + * Call this after calling constructor for xsltFile only above. + * + * @param result + * of transform + */ + public void initResult(Result result) { + transformerHandler.setResult(result); + } + + /******************** start of ContentHandler ***************************/ + /** {@inheritDoc} */ + public void setDocumentLocator(Locator locator) { + if (transformerHandler != null) { + transformerHandler.setDocumentLocator(locator); + } + } + + /** {@inheritDoc} */ + public void startDocument() throws SAXException { + if (transformerHandler != null) { + transformerHandler.startDocument(); + } + } + + /** {@inheritDoc} */ + public void endDocument() throws SAXException { + if (transformerHandler != null) { + transformerHandler.endDocument(); + } + } + + /** {@inheritDoc} */ + public void processingInstruction(String target, String data) throws SAXException { + if (transformerHandler != null) { + transformerHandler.processingInstruction(target, data); + } + } + + /** {@inheritDoc} */ + public void startElement(String uri, String local, String raw, Attributes attrs) + throws SAXException { + AttributesImpl ai = new AttributesImpl(attrs); + if (transformerHandler != null) { + transformerHandler.startElement(uri, local, raw, ai); + } + } + + /** {@inheritDoc} */ + public void characters(char[] ch, int start, int length) throws SAXException { + if (transformerHandler != null) { + transformerHandler.characters(ch, start, length); + } + } + + /** {@inheritDoc} */ + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + if (transformerHandler != null) { + transformerHandler.ignorableWhitespace(ch, start, length); + } + } + + /** {@inheritDoc} */ + public void endElement(String uri, String local, String raw) throws SAXException { + if (transformerHandler != null) { + transformerHandler.endElement(uri, local, raw); + } + } + + /** {@inheritDoc} */ + public void skippedEntity(String string) throws SAXException { + if (transformerHandler != null) { + transformerHandler.skippedEntity(string); + } + } + + /** {@inheritDoc} */ + public void startPrefixMapping(String string, String string1) throws SAXException { + if (transformerHandler != null) { + transformerHandler.startPrefixMapping(string, string1); + } + } + + /** {@inheritDoc} */ + public void endPrefixMapping(String string) throws SAXException { + if (transformerHandler != null) { + transformerHandler.endPrefixMapping(string); + } + } + + /***************************** LexicalHandlerImpl **************************/ + /** + * @param name + * - param1 + * @param pid + * - param2 + * @param lid + * - param3 + * @throws SAXException + * - if parser fails + */ + public void startDTD(String name, String pid, String lid) throws SAXException { + if (transformerHandler != null) { + transformerHandler.startDTD(name, pid, lid); + } + } + + /** + * End of DTD + * + * @throws SAXException + * - if parser fails + */ + public void endDTD() throws SAXException { + if (transformerHandler != null) { + transformerHandler.endDTD(); + } + } + + /** + * startEnitity. + * + * @param string + * - param 1 + * @throws SAXException + * - if parser fails + */ + public void startEntity(String string) throws SAXException { + if (transformerHandler != null) { + transformerHandler.startEntity(string); + } + } + + /** + * end Entity + * + * @param string + * - param 1 + * @throws SAXException + * - if paser fails + */ + public void endEntity(String string) throws SAXException { + if (transformerHandler != null) { + transformerHandler.endEntity(string); + } + } + + /** + * Start of CDATA section + * + * @throws SAXException + * - parser fails + */ + public void startCDATA() throws SAXException { + if (transformerHandler != null) { + transformerHandler.startCDATA(); + } + } + + /** + * endCDATA section + * + * @throws SAXException + * - if paser fails + */ + public void endCDATA() throws SAXException { + if (transformerHandler != null) { + transformerHandler.endCDATA(); + } + } + + /** + * + * @param charArray + * - the characters + * @param int1 + * - param 2 + * @param int2 + * - param 3 + * @throws SAXException + * - if paser fails + */ + public void comment(char[] charArray, int int1, int int2) throws SAXException { + if (transformerHandler != null) { + transformerHandler.comment(charArray, int1, int2); + } + } + + /******************** End of Lexical Handler ***********************/ +} diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java new file mode 100644 index 000000000..8e02c67cd --- /dev/null +++ b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java @@ -0,0 +1,115 @@ +/* + * 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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; + +/** + * An extension of TransformerNode used to run 2nd transform after completion of first + */ +class TransformerNodeEndProcessing extends TransformerNode { + + private final ByteArrayOutputStream enrichedFOBuffer = new ByteArrayOutputStream(); + private DefaultHandler delegateHandler = null; + private final FOUserAgent userAgent; + + /** + * Do a transform, but perform special processing at the end for the access + * stuff. + * + * @param xsltTemplates Transform to do. + * @param fopHandler Used in the end processing + * @param userAgent the userAgent + * @throws FOPException + * if transform fails + */ + public TransformerNodeEndProcessing(Templates xsltTemplates, DefaultHandler fopHandler, + FOUserAgent userAgent) throws FOPException { + super(xsltTemplates); + delegateHandler = fopHandler; + this.userAgent = userAgent; + Result res1 = new StreamResult(enrichedFOBuffer); + super.initResult(res1); + } + + /** + * Do a transform, but perform special processing at the end for the access + * stuff. + * + * @param xsltFile Transform to do. + * @param fopHandler Used in the end processing + * @param userAgent the userAgent + * @throws FOPException if transform fails + */ + + public TransformerNodeEndProcessing(Source xsltFile, DefaultHandler fopHandler, + FOUserAgent userAgent) throws FOPException { + super(xsltFile); + delegateHandler = fopHandler; + this.userAgent = userAgent; + Result res1 = new StreamResult(enrichedFOBuffer); + super.initResult(res1); + } + + /** {@inheritDoc} */ + public void endDocument() throws SAXException { + super.endDocument(); + // do the second transform to struct + try { + //TODO this must be optimized, no buffering (ex. SAX-based tee-proxy) + byte[] enrichedFO = enrichedFOBuffer.toByteArray(); + Transformer transformer = AccessibilityUtil.getReduceFOTreeTemplates().newTransformer(); + Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Result res = new StreamResult(out); + transformer.transform(src, res); + userAgent.setReducedFOTree(out.toByteArray()); + + SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setValidating(false); + SAXParser saxParser = saxParserFactory.newSAXParser(); + InputStream in = new ByteArrayInputStream(enrichedFO); + saxParser.parse(in, delegateHandler); + } catch (Exception e) { + // TODO Auto-generated catch block + throw new SAXException(e); + } + + } + +} diff --git a/src/java/org/apache/fop/accessibility/addPtr.xsl b/src/java/org/apache/fop/accessibility/addPtr.xsl new file mode 100644 index 000000000..f619817cd --- /dev/null +++ b/src/java/org/apache/fop/accessibility/addPtr.xsl @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/java/org/apache/fop/accessibility/reduceFOTree.xsl b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl new file mode 100644 index 000000000..eb808286b --- /dev/null +++ b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index ebd2e0594..1e0e3fb86 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -99,6 +99,9 @@ public class FOUserAgent { private boolean locatorEnabled = true; // true by default (for error messages). private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); + //TODO Verify that a byte array is the best solution here + private byte[] reducedFOTree; // accessibility: reduced FO + /** Producer: Metadata element for the system/software that produces * the document. (Some renderers can store this in the document.) */ @@ -153,6 +156,9 @@ public class FOUserAgent { setBaseURL(factory.getBaseURL()); setFontBaseURL(factory.getFontManager().getFontBaseURL()); setTargetResolution(factory.getTargetResolution()); + if (this.getRendererOptions().get("accessibility") == null) { + this.rendererOptions.put("accessibility", Boolean.FALSE); + } } /** @return the associated FopFactory instance */ @@ -197,6 +203,7 @@ public class FOUserAgent { return rendererOverride; } + /** * Sets an explicit FOEventHandler instance which overrides the one * defined by the render type setting. @@ -615,5 +622,34 @@ public class FOUserAgent { } + /** + * check if accessibility is enabled + * @return boolean + */ + public boolean accessibilityEnabled() { + Boolean enabled = (Boolean)this.getRendererOptions().get("accessibility"); + if (enabled != null) { + return enabled.booleanValue(); + } else { + return false; + } + } + + /** + * Used for accessibility. Stores the reduced FO tree (the result from the second transform) + * for later use. + * @param reducedFOTree the result from 2nd transform + */ + public void setReducedFOTree(byte[] reducedFOTree) { + this.reducedFOTree = reducedFOTree; + } + + /** + * Used for accessibility. Returns the reduced FO tree. + * @return result from 2nd transform as byte array + */ + public byte[] getReducedFOTree() { + return this.reducedFOTree; + } } diff --git a/src/java/org/apache/fop/apps/Fop.java b/src/java/org/apache/fop/apps/Fop.java index 0527ea290..e5927fdba 100644 --- a/src/java/org/apache/fop/apps/Fop.java +++ b/src/java/org/apache/fop/apps/Fop.java @@ -24,6 +24,7 @@ import java.io.OutputStream; import org.xml.sax.helpers.DefaultHandler; +import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.fo.FOTreeBuilder; /** @@ -110,7 +111,11 @@ public class Fop { if (foTreeBuilder == null) { createDefaultHandler(); } - return this.foTreeBuilder; + if (this.foUserAgent.accessibilityEnabled()) { + return AccessibilityUtil.decorateDefaultHandler(this.foTreeBuilder, foUserAgent); + } else { + return this.foTreeBuilder; + } } /** diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 96c22f964..cf22a1e56 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -99,6 +99,11 @@ public class FopFactory implements ImageContext { * external-graphics. */ private String base = null; + + /** + * Controls if accessibility is turned on or off + */ + private boolean accessibility = false; /** The base URL for all hyphen URL resolutions. */ private String hyphenBase = null; @@ -181,9 +186,18 @@ public class FopFactory implements ImageContext { */ public FOUserAgent newFOUserAgent() { FOUserAgent userAgent = new FOUserAgent(this); + userAgent.getRendererOptions().put("accessibility", Boolean.valueOf(this.accessibility)); return userAgent; } + /** + * Used for accessibility to pass value to newFOUserAgent + * @param value set through xconf file + */ + void setAccessibility(boolean value) { + this.accessibility = value; + } + /** * Returns a new {@link Fop} instance. FOP will be configured with a default user agent * instance. diff --git a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java index e71173845..e6f1aff16 100644 --- a/src/java/org/apache/fop/apps/FopFactoryConfigurator.java +++ b/src/java/org/apache/fop/apps/FopFactoryConfigurator.java @@ -90,6 +90,15 @@ public class FopFactoryConfigurator { log.debug("Initializing FopFactory Configuration"); } + if (cfg.getChild("accessibility", false) != null) { + try { + this.factory.setAccessibility( + cfg.getChild("accessibility").getValueAsBoolean()); + } catch (ConfigurationException e) { + throw new FOPException(e); + } + } + // strict configuration if (cfg.getChild("strict-configuration", false) != null) { try { diff --git a/src/java/org/apache/fop/area/Trait.java b/src/java/org/apache/fop/area/Trait.java index 45c0432f4..27ce39252 100644 --- a/src/java/org/apache/fop/area/Trait.java +++ b/src/java/org/apache/fop/area/Trait.java @@ -194,9 +194,12 @@ public class Trait implements Serializable { public static final Integer OVERLINE_COLOR = new Integer(35); /** Trait for color of linethrough decorations when rendering inline parent. */ public static final Integer LINETHROUGH_COLOR = new Integer(36); + + /** The ptr trait. Used for accessibility */ + public static final Integer PTR = new Integer(37); /** Maximum value used by trait keys */ - public static final int MAX_TRAIT_KEY = 36; + public static final int MAX_TRAIT_KEY = 37; private static final TraitInfo[] TRAIT_INFO = new TraitInfo[MAX_TRAIT_KEY + 1]; @@ -225,6 +228,7 @@ public class Trait implements Serializable { static { // Create a hashmap mapping trait code to name for external representation //put(ID_LINK, new TraitInfo("id-link", String.class)); + put(PTR, new TraitInfo("ptr", String.class)); put(INTERNAL_LINK, new TraitInfo("internal-link", InternalLink.class)); put(EXTERNAL_LINK, new TraitInfo("external-link", ExternalLink.class)); put(FONT, new TraitInfo("font", FontTriplet.class)); diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index fef2a1f46..734cd9b98 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -327,6 +327,8 @@ public class CommandLineOptions { i = i + parseAreaTreeOption(args, i); } else if (args[i].equals("-if")) { i = i + parseIntermediateFormatOption(args, i); + } else if (args[i].equals("-a")) { + this.renderingOptions.put("accessibility", Boolean.TRUE); } else if (args[i].equals("-v")) { printVersion(); return false; @@ -1129,6 +1131,7 @@ public class CommandLineOptions { + " -nocopy PDF file will be encrypted without copy content permission\n" + " -noedit PDF file will be encrypted without edit content permission\n" + " -noannotations PDF file will be encrypted without edit annotation permission\n" + + " -a enables accessibility features (Tagged PDF etc., default off)\n" + " -pdfprofile prof PDF file will be generated with the specified profile\n" + " (Examples for prof: PDF/A-1b or PDF/X-3:2003)\n\n" + " [INPUT] \n" diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index a1ccb20e7..8bcaa1538 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -771,8 +771,16 @@ public interface Constants { * multi-column layouts. */ int PR_X_DISABLE_COLUMN_BALANCING = 273; + /** Property constant - FOP proprietary: FOP internal use for accessibility */ + int PR_X_PTR = 274; + /** + * Property constant - FOP proprietary: alternative text for e-g and i-f-o. + * Used for accessibility. + */ + int PR_X_ALT_TEXT = 275; + /** Number of property constants defined */ - int PROPERTY_COUNT = 273; + int PROPERTY_COUNT = 275; // compound property constants diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index 07d8f472c..8c4e3416d 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -36,6 +36,7 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; 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.fo.extensions.svg.SVGElementMapping; import org.apache.fop.fo.pagination.Root; import org.apache.fop.util.CharUtilities; @@ -419,6 +420,8 @@ public abstract class FONode implements Cloneable { return "fo:" + localName; } else if (namespaceURI.equals(ExtensionElementMapping.URI)) { return "fox:" + localName; + } else if (namespaceURI.equals(InternalElementMapping.URI)) { + return "foi:" + localName; // used FOP internally for accessibility } else if (namespaceURI.equals(SVGElementMapping.URI)) { return "svg:" + localName; } else { diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index b4a864e43..d214dee99 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -2515,6 +2515,18 @@ public final class FOPropertyMapping implements Constants { m.setDefault(""); addPropertyMaker("id", m); + // foi:ptr, used for accessibility + m = new StringProperty.Maker(PR_X_PTR); + m.setInherited(false); + m.setDefault(""); + addPropertyMaker("foi:ptr", m); + + // fox:alt, used for accessibility + m = new StringProperty.Maker(PR_X_ALT_TEXT); + m.setInherited(false); + m.setDefault(""); + addPropertyMaker("fox:alt-text", m); + // provisional-label-separation m = new LengthProperty.Maker(PR_PROVISIONAL_LABEL_SEPARATION); m.setInherited(true); diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index 927bed0f7..ee2b3886e 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -46,6 +46,8 @@ public class ExtensionElementMapping extends ElementMapping { propertyAttributes.add("orphan-content-limit"); propertyAttributes.add("internal-destination"); propertyAttributes.add("disable-column-balancing"); + //These are FOP's extension properties for accessibility + propertyAttributes.add("alt"); } /** diff --git a/src/java/org/apache/fop/fo/extensions/ExternalDocument.java b/src/java/org/apache/fop/fo/extensions/ExternalDocument.java index bea6f6f61..233714bd7 100644 --- a/src/java/org/apache/fop/fo/extensions/ExternalDocument.java +++ b/src/java/org/apache/fop/fo/extensions/ExternalDocument.java @@ -31,7 +31,7 @@ import org.apache.fop.fo.pagination.AbstractPageSequence; import org.apache.fop.fo.properties.LengthRangeProperty; /** - * Class for the fox:external-document extenstion element. + * Class for the fox:external-document extension element. */ public class ExternalDocument extends AbstractPageSequence implements GraphicsProperties { diff --git a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java new file mode 100644 index 000000000..c6802b5b3 --- /dev/null +++ b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.extensions; + +import java.util.HashMap; +import java.util.Set; + +import org.apache.xmlgraphics.util.QName; + +import org.apache.fop.fo.ElementMapping; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.UnknownXMLObj; +import org.apache.fop.fo.extensions.destination.Destination; + +/** + * Element mapping for FOP's internal extension to XSL-FO. + */ +public class InternalElementMapping extends ElementMapping { + + /** The FOP extension namespace URI */ + public static final String URI = "http://xmlgraphics.apache.org/fop/internal"; + + private static final Set propertyAttributes = new java.util.HashSet(); + + static { + //These are FOP's extension properties for accessibility + propertyAttributes.add("ptr"); + } + + /** + * Constructor. + */ + public InternalElementMapping() { + namespaceURI = URI; + } + + /** + * Initialize the data structures. + */ + protected void initialize() { + if (foObjs == null) { + foObjs = new HashMap(); + } + } + + /* static class DestinationMaker extends ElementMapping.Maker { + public FONode make(FONode parent) { + return new Destination(parent); + } + } */ + + + /** + * used internally for accessibility + */ + public String getStandardPrefix() { + return "foi"; + } + + /** {@inheritDoc} */ + public boolean isAttributeProperty(QName attributeName) { + if (!URI.equals(attributeName.getNamespaceURI())) { + throw new IllegalArgumentException("The namespace URIs don't match"); + } + return propertyAttributes.contains(attributeName.getLocalName()); + } + +} diff --git a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java index d72682282..2ed576a32 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java +++ b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java @@ -60,6 +60,7 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie private int scaling; private int textAlign; private Length width; + private String ptr; // used for accessibility // Unused but valid items, commented out for performance: // private CommonAccessibility commonAccessibility; // private CommonAural commonAural; @@ -94,6 +95,7 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); height = pList.get(PR_HEIGHT).getLength(); id = pList.get(PR_ID).getString(); + ptr = pList.get(PR_X_PTR).getString(); // used for accessibility inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange(); keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); @@ -207,6 +209,11 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie return keepWithPrevious; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** @return the graphic's intrinsic width in millipoints */ public abstract int getIntrinsicWidth(); diff --git a/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java index 5f420efb8..3554c8e0e 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java +++ b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java @@ -51,6 +51,7 @@ public abstract class AbstractPageNumberCitation extends FObj { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; + private String ptr; // used for accessibility // private ToBeImplementedProperty letterSpacing; private SpaceProperty lineHeight; private String refId; @@ -96,6 +97,7 @@ public abstract class AbstractPageNumberCitation extends FObj { dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); // letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); + ptr = pList.get(PR_X_PTR).getString(); // used for accessibility refId = pList.get(PR_REF_ID).getString(); textDecoration = pList.getTextDecorationProps(); // textShadow = pList.get(PR_TEXT_SHADOW); @@ -138,6 +140,11 @@ public abstract class AbstractPageNumberCitation extends FObj { return textDecoration; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** @return the "alignment-adjust" property */ public Length getAlignmentAdjust() { return alignmentAdjust; diff --git a/src/java/org/apache/fop/fo/flow/BasicLink.java b/src/java/org/apache/fop/fo/flow/BasicLink.java index ee3171188..2fe0c9a8d 100644 --- a/src/java/org/apache/fop/fo/flow/BasicLink.java +++ b/src/java/org/apache/fop/fo/flow/BasicLink.java @@ -65,6 +65,7 @@ public class BasicLink extends Inline { /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); + // destinationPlacementOffset = pList.get(PR_DESTINATION_PLACEMENT_OFFSET); externalDestination = pList.get(PR_EXTERNAL_DESTINATION).getString(); // indicateDestination = pList.get(PR_INDICATE_DESTINATION); @@ -158,6 +159,11 @@ public class BasicLink extends Inline { return this.showDestination; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return super.getPtr(); + } + /** {@inheritDoc} */ public String getLocalName() { return "basic-link"; diff --git a/src/java/org/apache/fop/fo/flow/Block.java b/src/java/org/apache/fop/fo/flow/Block.java index daaebd6d0..efcd18b71 100644 --- a/src/java/org/apache/fop/fo/flow/Block.java +++ b/src/java/org/apache/fop/fo/flow/Block.java @@ -71,6 +71,7 @@ public class Block extends FObjMixed implements BreakPropertySet { private int lineHeightShiftAdjustment; private int lineStackingStrategy; private Numeric orphans; + private String ptr; //used for accessibility private int whiteSpaceTreatment; private int span; private int textAlign; @@ -122,6 +123,7 @@ public class Block extends FObjMixed implements BreakPropertySet { lineHeightShiftAdjustment = pList.get(PR_LINE_HEIGHT_SHIFT_ADJUSTMENT).getEnum(); lineStackingStrategy = pList.get(PR_LINE_STACKING_STRATEGY).getEnum(); orphans = pList.get(PR_ORPHANS).getNumeric(); + ptr = pList.get(PR_X_PTR).getString(); //used for accessibility whiteSpaceTreatment = pList.get(PR_WHITE_SPACE_TREATMENT).getEnum(); span = pList.get(PR_SPAN).getEnum(); textAlign = pList.get(PR_TEXT_ALIGN).getEnum(); @@ -171,6 +173,11 @@ public class Block extends FObjMixed implements BreakPropertySet { return breakAfter; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** @return the "break-before" property. */ public int getBreakBefore() { return breakBefore; diff --git a/src/java/org/apache/fop/fo/flow/Character.java b/src/java/org/apache/fop/fo/flow/Character.java index f76b3225d..636b2b1c7 100644 --- a/src/java/org/apache/fop/fo/flow/Character.java +++ b/src/java/org/apache/fop/fo/flow/Character.java @@ -62,6 +62,7 @@ public class Character extends FObj { private CommonTextDecoration textDecoration; // private ToBeImplementedProperty textShadow; private Property wordSpacing; + private String ptr; // used for accessibility // Unused but valid items, commented out for performance: // private CommonAural commonAural; // private CommonMarginInline commonMarginInline; @@ -108,6 +109,7 @@ public class Character extends FObj { lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); textDecoration = pList.getTextDecorationProps(); wordSpacing = pList.get(PR_WORD_SPACING); + ptr = pList.get(PR_X_PTR).getString(); // used for accessibility } /** {@inheritDoc} */ @@ -207,6 +209,11 @@ public class Character extends FObj { return keepWithPrevious; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** {@inheritDoc} */ public String getLocalName() { return "character"; diff --git a/src/java/org/apache/fop/fo/flow/Inline.java b/src/java/org/apache/fop/fo/flow/Inline.java index dae7d306b..ea5b49baf 100644 --- a/src/java/org/apache/fop/fo/flow/Inline.java +++ b/src/java/org/apache/fop/fo/flow/Inline.java @@ -37,6 +37,7 @@ public class Inline extends InlineLevel { private Length alignmentAdjust; private int alignmentBaseline; private Length baselineShift; + private String ptr; // used for accessibility private int dominantBaseline; // Unused but valid items, commented out for performance: // private CommonRelativePosition commonRelativePosition; @@ -66,6 +67,7 @@ public class Inline extends InlineLevel { alignmentBaseline = pList.get(PR_ALIGNMENT_BASELINE).getEnum(); baselineShift = pList.get(PR_BASELINE_SHIFT).getLength(); dominantBaseline = pList.get(PR_DOMINANT_BASELINE).getEnum(); + ptr = pList.get(PR_X_PTR).getString(); // used for accessibility } /** {@inheritDoc} */ @@ -144,6 +146,11 @@ public class Inline extends InlineLevel { return dominantBaseline; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** {@inheritDoc} */ public String getLocalName() { return "inline"; diff --git a/src/java/org/apache/fop/fo/flow/PageNumber.java b/src/java/org/apache/fop/fo/flow/PageNumber.java index dc834d708..bb251f44f 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumber.java +++ b/src/java/org/apache/fop/fo/flow/PageNumber.java @@ -47,6 +47,7 @@ public class PageNumber extends FObj { private int alignmentBaseline; private Length baselineShift; private int dominantBaseline; + private String ptr; // used for accessibility // private ToBeImplementedProperty letterSpacing; private SpaceProperty lineHeight; /** Holds the text decoration values. May be null */ @@ -92,6 +93,7 @@ public class PageNumber extends FObj { // letterSpacing = pList.get(PR_LETTER_SPACING); lineHeight = pList.get(PR_LINE_HEIGHT).getSpace(); textDecoration = pList.getTextDecorationProps(); + ptr = pList.get(PR_X_PTR).getString(); // used for accessibility // textShadow = pList.get(PR_TEXT_SHADOW); // implicit properties @@ -165,6 +167,11 @@ public class PageNumber extends FObj { return lineHeight; } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** {@inheritDoc} */ public String getLocalName() { return "page-number"; diff --git a/src/java/org/apache/fop/fo/flow/table/TableFObj.java b/src/java/org/apache/fop/fo/flow/table/TableFObj.java index ec508580c..96b3769a3 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java @@ -46,6 +46,7 @@ public abstract class TableFObj extends FObj { private Numeric borderBeforePrecedence; private Numeric borderEndPrecedence; private Numeric borderStartPrecedence; + private String ptr; ConditionalBorder borderBefore; ConditionalBorder borderAfter; @@ -71,6 +72,7 @@ public abstract class TableFObj extends FObj { borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); + ptr = pList.get(PR_X_PTR).getString(); if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java && getNameId() != FO_TABLE_CELL && getCommonBorderPaddingBackground().hasPadding( @@ -235,6 +237,11 @@ public abstract class TableFObj extends FObj { } } + /** @return the "foi:ptr" property. */ + public String getPtr() { + return ptr; + } + /** * Prepares the borders of this element if the collapsing-border model is in use. * Conflict resolution with parent elements is done where applicable. diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java index c641c3e69..acfcbe3f0 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -385,6 +385,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + TraitSetter.addPtr(curBlockArea, getBlockFO().getPtr()); // used for accessibility TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), effSpaceBefore, effSpaceAfter); flush(); diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java index 9cab6322b..d062ba2ca 100644 --- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java +++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java @@ -583,6 +583,17 @@ public class TraitSetter { } } + /** + * Adds the ptr trait to the area. + * @param area the area to set the traits on + * @param ptr string + */ + public static void addPtr(Area area, String ptr) { + if (ptr != null && ptr.length() > 0) { + area.addTrait(Trait.PTR, ptr); + } + } + /** * Sets the producer's ID as a trait on the area. This can be used to track back the * generating FO node. diff --git a/src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java index 00c628a40..fd4d803af 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/AbstractGraphicsLayoutManager.java @@ -85,6 +85,7 @@ public abstract class AbstractGraphicsLayoutManager extends LeafNodeLayoutManage transferForeignAttributes(viewportArea); Viewport vp = new Viewport(viewportArea); + TraitSetter.addPtr(vp, fobj.getPtr()); // used for accessibility TraitSetter.setProducerID(vp, fobj.getId()); vp.setIPD(imageLayout.getViewportSize().width); vp.setBPD(imageLayout.getViewportSize().height); diff --git a/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java index b65978453..a74fac743 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/AbstractPageNumberCitationLayoutManager.java @@ -138,6 +138,7 @@ public abstract class AbstractPageNumberCitationLayoutManager extends LeafNodeLa text.setBaselineOffset(font.getAscender()); TraitSetter.addFontTraits(text, font); text.addTrait(Trait.COLOR, fobj.getColor()); + TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); } diff --git a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java index c369df82b..e1f7475e9 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java @@ -56,6 +56,7 @@ public class BasicLinkLayoutManager extends InlineLayoutManager { private void setupBasicLinkArea(InlineArea area) { BasicLink fobj = (BasicLink) this.fobj; // internal destinations take precedence: + area.addTrait(Trait.PTR, fobj.getPtr()); // used for accessibility if (fobj.hasInternalDestination()) { String idref = fobj.getInternalDestination(); PageSequenceLayoutManager pslm = getPSLM(); diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java index 383ca0105..dcd993487 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java @@ -86,6 +86,7 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager { } TraitSetter.setProducerID(text, node.getId()); TraitSetter.addTextDecoration(text, node.getTextDecoration()); + TraitSetter.addPtr(text, node.getPtr()); // used for accessibility return text; } diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java index dc8a020ae..5cae07207 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java @@ -85,7 +85,7 @@ public class PageNumberLayoutManager extends LeafNodeLayoutManager { text.setBaselineOffset(font.getAscender()); TraitSetter.addFontTraits(text, font); text.addTrait(Trait.COLOR, fobj.getColor()); - + TraitSetter.addPtr(text, fobj.getPtr()); // used for accessibility TraitSetter.addTextDecoration(text, fobj.getTextDecoration()); return text; diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index 27ed38b53..5c24dbfcb 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -25,10 +25,12 @@ import java.util.ListIterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.area.Trait; import org.apache.fop.area.inline.TextArea; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FOText; +import org.apache.fop.fo.FObj; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontSelector; import org.apache.fop.layoutmgr.InlineKnuthSequence; @@ -504,12 +506,28 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } TraitSetter.addFontTraits(textArea, font); textArea.addTrait(Trait.COLOR, this.foText.getColor()); - + textArea.addTrait(Trait.PTR, getPtr()); // used for accessibility TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration()); return textArea; } + /** + * used for accessibility + * @return ptr of fobj + */ + private String getPtr() { + FObj fobj = this.parentLM.getFObj(); + if (fobj instanceof org.apache.fop.fo.flow.Block) { + return (((org.apache.fop.fo.flow.Block) fobj).getPtr()); + } else if (fobj instanceof org.apache.fop.fo.flow.Inline) { + return (((org.apache.fop.fo.flow.Inline) fobj).getPtr()); + } else { + log.warn("Accessibility: TLM.getPtr-no Ptr found"); + return ""; + } + } + private void addToLetterAdjust(final int index, final int width) { if (this.letterAdjustArray[index] == null) { this.letterAdjustArray[index] = new MinOptMax(width); diff --git a/src/java/org/apache/fop/pdf/PDFArray.java b/src/java/org/apache/fop/pdf/PDFArray.java index 7c5f8ba9b..a7dfc388e 100644 --- a/src/java/org/apache/fop/pdf/PDFArray.java +++ b/src/java/org/apache/fop/pdf/PDFArray.java @@ -106,6 +106,15 @@ public class PDFArray extends PDFObject { } } + /** + * Indicates whether the given object exists in the array. + * @param obj the object to look for + * @return true if obj is contained + */ + public boolean contains(Object obj) { + return this.values.contains(obj); + } + /** * Returns the length of the array * @return the length of the array diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index 0a4516ce6..087ae4277 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -177,24 +177,49 @@ public class PDFFactory { * @param pageWidth width of the page in points * @param pageHeight height of the page in points * @param pageIndex index of the page (zero-based) + * @param currentPageParentKey the integer key in the structural parent tree * * @return the created /Page object */ public PDFPage makePage(PDFResources resources, - int pageWidth, int pageHeight, int pageIndex) { - + int pageWidth, int pageHeight, int pageIndex, + int currentPageParentKey) { /* * create a PDFPage with the next object number, the given * resources, contents and dimensions */ - PDFPage page = new PDFPage(resources, + PDFPage page = new PDFPage(resources, // old numPages pageWidth, pageHeight, pageIndex); + if (currentPageParentKey > -1) { + //Accessibility is enabled + page.setStructParents(currentPageParentKey); + //This is a PDF 1.5 feature. It is set as a work-around for a bug in Adobe Acrobat + //which reports this missing even if the PDF file is PDF 1.4. + page.setTabs(new PDFName("S")); + } getDocument().assignObjectNumber(page); getDocument().getPages().addPage(page); return page; } + /** + * Make a /Page object. The page is assigned an object number immediately + * so references can already be made. The page must be added to the + * PDFDocument later using addObject(). + * + * @param resources resources object to use + * @param pageWidth width of the page in points + * @param pageHeight height of the page in points + * @param pageIndex index of the page (zero-based) + * + * @return the created /Page object + */ + public PDFPage makePage(PDFResources resources, + int pageWidth, int pageHeight, int pageIndex) { + return makePage(resources, pageWidth, pageHeight, pageIndex, -1); + } + /** * Make a /Page object. The page is assigned an object number immediately * so references can already be made. The page must be added to the @@ -867,6 +892,17 @@ public class PDFFactory { return pageLabels; } + /** + * Creates and returns a StructTreeRoot object. Used for accessibility. + * @return structure Tree Root element + */ + public PDFStructTreeRoot makeStructTreeRoot() { + PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(); + getDocument().assignObjectNumber(structTreeRoot); + getDocument().addTrailerObject(structTreeRoot); + return structTreeRoot; + } + /** * Make a the head object of the name dictionary (the /Dests object). * diff --git a/src/java/org/apache/fop/pdf/PDFLink.java b/src/java/org/apache/fop/pdf/PDFLink.java index a7c4c6548..620e5d51d 100644 --- a/src/java/org/apache/fop/pdf/PDFLink.java +++ b/src/java/org/apache/fop/pdf/PDFLink.java @@ -42,6 +42,7 @@ public class PDFLink extends PDFObject { private float bry; private String color; private PDFAction action; + private Integer structParent; /** * create objects associated with a link annotation (GoToR) @@ -68,6 +69,15 @@ public class PDFLink extends PDFObject { this.action = action; } + + /** + * Used for accessibility + * @param mcid of this structParent + */ + public void setStructParent(int mcid) { + this.structParent = new Integer(mcid); + } + /** * {@inheritDoc} */ @@ -87,6 +97,8 @@ public class PDFLink extends PDFObject { + (brx) + " " + (bry) + " ]\n" + "/C [ " + this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A " + this.action.getAction() + "\n" + "/H /I\n" + + (this.structParent != null + ? "/StructParent " + this.structParent.toString() + "\n" : "") + fFlag + "\n>>\nendobj\n"; return s; } diff --git a/src/java/org/apache/fop/pdf/PDFPage.java b/src/java/org/apache/fop/pdf/PDFPage.java index d1472e154..6cc8c3e57 100644 --- a/src/java/org/apache/fop/pdf/PDFPage.java +++ b/src/java/org/apache/fop/pdf/PDFPage.java @@ -146,4 +146,21 @@ public class PDFPage extends PDFResourceContext { return this.pageIndex; } + /** + * Sets the "StructParents" value. + * @param structParents the integer key of this object's entry in the structural parent tree. + */ + public void setStructParents(int structParents) { + put("StructParents", structParents); + } + + /** + * Specifies the tab order for annotations on a page. + * @param value one of the allowed values (see PDF 1.5) + * @since PDF 1.5 + */ + public void setTabs(PDFName value) { + put("Tabs", value); + } + } diff --git a/src/java/org/apache/fop/pdf/PDFParentTree.java b/src/java/org/apache/fop/pdf/PDFParentTree.java new file mode 100644 index 000000000..7528aa299 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFParentTree.java @@ -0,0 +1,50 @@ +/* + * 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.pdf; + +/** + * Class representing a PDF /ParentTree + */ +public class PDFParentTree extends PDFNumberTreeNode { + + /** + * Create the /ParentTree NumberTreeNode + */ + public PDFParentTree() { + super(); + } + + /** + * Get the parentTree. + * @return parentTree as PDFNumsArray + */ + public PDFNumsArray getNums() { + PDFNumsArray nums = super.getNums(); + if (nums == null) { + nums = new PDFNumsArray(this); + setNums(nums); + } + return nums; + } +} + + + + diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java index 1ea316390..c8d94585c 100644 --- a/src/java/org/apache/fop/pdf/PDFRoot.java +++ b/src/java/org/apache/fop/pdf/PDFRoot.java @@ -63,7 +63,7 @@ public class PDFRoot extends PDFDictionary { */ public PDFRoot(int objnum, PDFPages pages) { super(); - setObjectNumber(objnum); + setObjectNumber(objnum); put("Type", new PDFName("Catalog")); setRootPages(pages); } @@ -252,4 +252,32 @@ public class PDFRoot extends PDFDictionary { put("Lang", lang); } + /** + * Sets the StructTreeRoot object. Used for accessibility. + * @param structTreeRoot of this document + */ + public void setStructTreeRoot(PDFStructTreeRoot structTreeRoot) { + if (structTreeRoot == null) { + throw new NullPointerException("structTreeRoot must not be null"); + } + put("StructTreeRoot", structTreeRoot); + } + + /** + * Returns the StructTreeRoot object. + * @return the structure tree root (or null if accessibility is not enabled) + */ + public PDFStructTreeRoot getStructTreeRoot() { + return (PDFStructTreeRoot)get("StructTreeRoot"); + } + + /** + * Marks this document as conforming to the Tagged PDF conventions. + */ + public void makeTagged() { + PDFDictionary dict = new PDFDictionary(); + dict.put("Marked", Boolean.TRUE); + put("MarkInfo", dict); //new PDFMarkInfo() + } + } diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java new file mode 100644 index 000000000..408b1f2c7 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -0,0 +1,196 @@ +/* + * 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.pdf; + +/** + * Class representing a PDF Structure Element. + */ +public class PDFStructElem extends PDFDictionary { + + private PDFObject parentObject = null; + private String source = ""; + private boolean level1 = false; + + /** + * Create the /StructTreeRoot dictionary + * @param fo passed in fo object + * @param parent Parent of this PDFStructElem + */ + public PDFStructElem(String fo, PDFObject parent) { + super(); + if (parent instanceof PDFStructElem) { + parentObject = (PDFStructElem) parent; + } + put("Type", new PDFName("StructElem")); + source = fo; + //TODO Move this into the render/pdf package. The PDF library shall not contain FO knowledge + if ("block".equals(fo)) { + put("S", new PDFName("P")); + } else if ("inline".equals(fo) || "wrapper".equals(fo) || "character".equals(fo)) { + put("S", new PDFName("Span")); + } else if ("table-cell".equals(fo)) { + PDFStructElem grandParent = (PDFStructElem) + ((PDFStructElem)parent).getParentStructElem(); + String s = grandParent.getSource(); + if ("table-header".equals(s)) { + put("S", new PDFName("TH")); + } else { + put("S", new PDFName("TD")); + } + } else if ("table-row".equals(fo)) { + put("S", new PDFName("TR")); + } else if ("root".equals(fo)) { + put("S", new PDFName("Document")); + } else if ("page-sequence".equals(fo)) { + put("S", new PDFName("Part")); + } else if ("flow".equals(fo) || "static-content".equals(fo)) { + put("S", new PDFName("Sect")); + } else if ("page-number".equals(fo) || "page-number-citation".equals(fo) + || "page-number-citation-last".equals(fo)) { + put("S", new PDFName("Quote")); + } else if ("external-graphic".equals(fo) || "instream-foreign-object".equals(fo)) { + put("S", new PDFName("Figure")); + } else if ("table".equals(fo)) { + put("S", new PDFName("Table")); + } else if ("table-body".equals(fo)) { + put("S", new PDFName("TBody")); + } else if ("table-header".equals(fo)) { + put("S", new PDFName("THead")); + } else if ("table-footer".equals(fo)) { + put("S", new PDFName("TFoot")); + } else if ("list-block".equals(fo)) { + put("S", new PDFName("L")); + } else if ("list-item".equals(fo)) { + put("S", new PDFName("LI")); + } else if ("list-item-label".equals(fo)) { + put("S", new PDFName("Lbl")); + } else if ("list-item-body".equals(fo)) { + put("S", new PDFName("LBody")); + } else if ("block-container".equals(fo)) { + put("S", new PDFName("Div")); + } else if ("basic-link".equals(fo)) { + put("S", new PDFName("Link")); + } else if ("footnote".equals(fo)) { + put("S", new PDFName("Note")); + } else if ("footnote-body".equals(fo)) { + put("S", new PDFName("Sect")); + } else if ("marker".equals(fo)) { + put("S", new PDFName("Private")); + } else { + log.error("Accessibility: PDFStructElem constructor is missing: " + fo); + } + setParent(parent); + if (!"external-graphic".equals(fo) && !"instream-foreign-object".equals(fo)) { + put("K", new PDFArray()); + } + } + + /** + * This method is called for PDFStructElements which are direct children of + * fo:static-content or fo:flow-section + */ + public void setLevel1() { + this.level1 = true; + } + + /** + * + * @return true if the PDFStructElement is a direct child of + * fo:static-content or fo:flow-section + */ + public boolean getLevel1() { + return this.level1; + } + + /** + * Get the parent + * @return PDFStructElem of parent + */ + public PDFObject getParentStructElem() { + return (PDFStructElem)this.parentObject; + } + + /** + * Set the parent for this StructElem + * @param parent to be added + */ + public void setParent(PDFObject parent) { + if (parent != null) { + put("P", new PDFReference(parent)); + } + } + + /** + * Get the source of this StructElem + * @return the source + */ + public String getSource() { + return source; + } + + /** + * The kids of this StructElem + * @return the kids + */ + public PDFArray getKids() { + return (PDFArray)get("K"); + } + + /** + * Add a kid to this strucElem + * @param kid to be added + */ + public void addKid(PDFObject kid) { + getKids().add(kid); + } + + /** + * Add a kid, but only if it does not already exist + * @param kid to be added + * @return true if kid did not already exist + */ + public boolean addUniqueKid(PDFObject kid) { + PDFArray mArray = getKids(); + if (!mArray.contains(kid)) { + getKids().add(kid); + return true; + } else { + return false; + } + } + + /** + * Add kid referenced through mcid integer + * used fo:external-graphic + * @param mcid of this kid + */ + public void addMCIDKid(int mcid) { + put("K", mcid); + } + + /** + * Add a page reference to this structElem + * @param pageObject to be added + */ + public void addPage(Object pageObject) { + put("Pg", (PDFObject) pageObject); + } + +} diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java new file mode 100644 index 000000000..e530b1582 --- /dev/null +++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java @@ -0,0 +1,67 @@ +/* + * 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.pdf; + +/** + * Class representing a PDF /StructTreeRoot dictionary. + */ +public class PDFStructTreeRoot extends PDFDictionary { + + /** + * Create the /StructTreeRoot dictionary. + */ + public PDFStructTreeRoot() { + super(); + put("Type", new PDFName("StructTreeRoot")); + put("K", new PDFArray()); + } + + /** + * Add parentTree entry. + * @param parentTree to be added + */ + public void addParentTree(PDFParentTree parentTree) { + put("ParentTree", parentTree); + } + + /** + * Get the kids. + * @return the kids + */ + public PDFArray getKids() { + return (PDFArray)get("K"); + } + + /** + * Returns the first child of the kids array (normally the structure tree root element) + * @return the first child + */ + public PDFObject getFirstChild() { + return (PDFObject)getKids().get(0); + } + + /** + * Adds a kid. + * @param kid to be added + */ + public void addKid(PDFObject kid) { + getKids().add(kid); + } +} \ No newline at end of file diff --git a/src/java/org/apache/fop/pdf/PDFTextUtil.java b/src/java/org/apache/fop/pdf/PDFTextUtil.java index 6640f9b80..bb8816995 100644 --- a/src/java/org/apache/fop/pdf/PDFTextUtil.java +++ b/src/java/org/apache/fop/pdf/PDFTextUtil.java @@ -48,6 +48,7 @@ public abstract class PDFTextUtil { public static final int TR_CLIP = 7; private boolean inTextObject = false; + private boolean artifactMode = false; private String startText; private String endText; private boolean useMultiByte; @@ -115,6 +116,15 @@ public abstract class PDFTextUtil { return inTextObject; } + /** + * Indicates whether we are in a text object and if that text object represents + * an artifact. + * @return true if in artifact-mode text object + */ + public boolean inArtifactMode() { + return this.artifactMode; + } + /** * Called when a new text object should be started. Be sure to call setFont() before * issuing any text painting commands. @@ -127,12 +137,52 @@ public abstract class PDFTextUtil { this.inTextObject = true; } + /** + * Begin of a regular text object, used for accessibility + * @param mcid of text object + * @param structElemType of parent + */ + public void beginTextObjectAccess(int mcid, String structElemType) { + if (inTextObject) { + throw new IllegalStateException("Already in text object"); + } + write(structElemType + " <>\nBDC\nBT\n"); + this.inTextObject = true; + } + + /** + * Begin of a text object marked as artifact (fo:leader in XSL-FO) text object. + * Used for accessibility. + */ + public void beginArtifactTextObject() { + if (inTextObject) { + throw new IllegalStateException("Already in text object"); + } + write("/Artifact\nBMC\nBT\n"); + this.inTextObject = true; + this.artifactMode = true; + } + /** * Called when a text object should be ended. */ public void endTextObject() { + endTextObject(false); + } + + /** + * Called when a text object should be ended. + * @param accessEnabled indicating if accessibility is turned on or not + */ + public void endTextObject(boolean accessEnabled) { checkInTextObject(); - write("ET\n"); + if (accessEnabled) { + write("ET\nEMC\n"); + } else { + write("ET\n"); + } + this.artifactMode = false; this.inTextObject = false; initValues(); } diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 54f6170db..8da4b3973 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -834,8 +834,10 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { * @param url the URI/URL of the image * @param pos the position of the image * @param foreignAttributes an optional Map with foreign attributes, may be null + * @param ptr used for accessibility */ - protected abstract void drawImage(String url, Rectangle2D pos, Map foreignAttributes); + protected abstract void drawImage(String url, Rectangle2D pos, Map foreignAttributes, + String ptr); /** * Draw an image at the indicated location. @@ -843,7 +845,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { * @param pos the position of the image */ protected final void drawImage(String url, Rectangle2D pos) { - drawImage(url, pos, null); + drawImage(url, pos, null, ""); } /** diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 943c8c9da..d7df7596d 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -737,11 +737,13 @@ public abstract class AbstractRenderer currentBPPosition += viewport.getOffset(); Rectangle2D contpos = viewport.getContentPosition(); if (content instanceof Image) { - renderImage((Image) content, contpos); + String ptr = (String) viewport.getTrait(Trait.PTR); + renderImage((Image) content, contpos, ptr); } else if (content instanceof Container) { renderContainer((Container) content); } else if (content instanceof ForeignObject) { - renderForeignObject((ForeignObject) content, contpos); + String ptr = (String) viewport.getTrait(Trait.PTR); + renderForeignObject((ForeignObject) content, contpos, ptr); } else if (content instanceof InlineBlockParent) { renderInlineBlockParent((InlineBlockParent) content); } @@ -754,9 +756,10 @@ public abstract class AbstractRenderer * * @param image The image * @param pos The target position of the image + * @param ptr used for accessibility * (todo) Make renderImage() protected */ - public void renderImage(Image image, Rectangle2D pos) { + public void renderImage(Image image, Rectangle2D pos, String ptr) { // Default: do nothing. // Some renderers (ex. Text) don't support images. } @@ -780,9 +783,10 @@ public abstract class AbstractRenderer * * @param fo The foreign object area * @param pos The target position of the foreign object + * @param ptr used for accessibility * (todo) Make renderForeignObject() protected */ - protected void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + protected void renderForeignObject(ForeignObject fo, Rectangle2D pos, String ptr) { // Default: do nothing. // Some renderers (ex. Text) don't support foreign objects. } diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index 0c2501b87..1816ff515 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -183,7 +183,7 @@ public class AFPPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { String name = documentHandler.getPageSegmentNameFor(uri); if (name != null) { float[] srcPts = {rect.x, rect.y}; @@ -195,7 +195,7 @@ public class AFPPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { drawImageUsingDocument(doc, rect); } @@ -312,7 +312,7 @@ public class AFPPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawText(int x, int y, final int letterSpacing, final int wordSpacing, final int[] dx, - final String text) throws IFException { + final String text, final String ptr) throws IFException { final int fontSize = this.state.getFontSize(); getPaintingState().setFontSize(fontSize); diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index d1d2bec3b..1967ae607 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -375,7 +375,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { + public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { uri = URISpecification.getURL(uri); paintingState.setImageUri(uri); @@ -506,7 +506,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust /** {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { - drawImage(image.getURL(), pos, image.getForeignAttributes()); + drawImage(image.getURL(), pos, image.getForeignAttributes(),""); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/intermediate/IFConstants.java b/src/java/org/apache/fop/render/intermediate/IFConstants.java index e7f7e1a00..4c9b9fc8d 100644 --- a/src/java/org/apache/fop/render/intermediate/IFConstants.java +++ b/src/java/org/apache/fop/render/intermediate/IFConstants.java @@ -50,4 +50,6 @@ public interface IFConstants extends XMLConstants { String EL_BORDER_RECT = "border-rect"; String EL_FONT = "font"; String EL_TEXT = "text"; + /** used for accessibility */ + String EL_STRUCTURE_TREE = "structure-tree"; } diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java index 6369b0251..163fe16a1 100644 --- a/src/java/org/apache/fop/render/intermediate/IFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java @@ -153,10 +153,11 @@ public interface IFPainter { * @param wordSpacing additional spacing between words (may be 0) * @param dx an array of adjustment values for each character in X-direction (may be null) * @param text the text + * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text) throws IFException; + int[] dx, String text, String ptr) throws IFException; /** * Restricts the current clipping region with the given rectangle. @@ -205,18 +206,20 @@ public interface IFPainter { * an fo:external-graphic in XSL-FO. * @param uri the image's URI * @param rect the rectangle in which the image shall be painted + * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ - void drawImage(String uri, Rectangle rect) throws IFException; + void drawImage(String uri, Rectangle rect, String ptr) throws IFException; /** * Draws an image (represented by a DOM document) inside a given rectangle. This is the * equivalent to an fo:instream-foreign-object in XSL-FO. * @param doc the DOM document containing the foreign object * @param rect the rectangle in which the image shall be painted + * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ - void drawImage(Document doc, Rectangle rect) throws IFException; + void drawImage(Document doc, Rectangle rect, String ptr) throws IFException; //Note: For now, all foreign objects are handled as DOM documents. At the moment, all known //implementations use a DOM anyway, so optimizing this to work with SAX wouldn't result in //any performance benefits. The IFRenderer itself has a DOM anyway. Only the IFParser could diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 92e71d105..47e24445c 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -481,7 +481,8 @@ public class IFParser implements IFConstants { s = lastAttributes.getValue("word-spacing"); int wordSpacing = (s != null ? Integer.parseInt(s) : 0); int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx"); - painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString()); + String ptr = lastAttributes.getValue("ptr"); // used for accessibility + painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString(), ptr); } public boolean ignoreCharacters() { @@ -576,9 +577,10 @@ public class IFParser implements IFConstants { int height = Integer.parseInt(lastAttributes.getValue("height")); Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); + String ptr = lastAttributes.getValue("ptr"); // used for accessibility if (foreignObject != null) { painter.drawImage(foreignObject, - new Rectangle(x, y, width, height)); + new Rectangle(x, y, width, height), ptr); foreignObject = null; } else { String uri = lastAttributes.getValue( @@ -586,7 +588,7 @@ public class IFParser implements IFConstants { if (uri == null) { throw new IFException("xlink:href is missing on image", null); } - painter.drawImage(uri, new Rectangle(x, y, width, height)); + painter.drawImage(uri, new Rectangle(x, y, width, height), ptr); } resetForeignAttributes(); inForeignObject = false; diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 558ddfab8..664f1324a 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -818,7 +818,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { currentIPPosition = saveIP; currentBPPosition = saveBP; - currentBPPosition += (int)(bv.getAllocBPD()); + currentBPPosition += (bv.getAllocBPD()); } viewportDimensionStack.pop(); } @@ -886,6 +886,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { // stuff we only need if a link must be created: Rectangle ipRect = null; AbstractAction action = null; + String ptr = (String) ip.getTrait(Trait.PTR); // used for accessibility // make sure the rect is determined *before* calling super! int ipp = currentIPPosition; int bpp = currentBPPosition + ip.getOffset(); @@ -929,6 +930,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { // warn if link trait found but not allowed, else create link if (linkTraitFound) { + action.setPtr(ptr); // used for accessibility Link link = new Link(action, ipRect); this.deferredLinks.add(link); } @@ -963,6 +965,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { String fontName = getInternalFontNameForArea(text); int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); + String ptr = (String)text.getTrait(Trait.PTR); // used for accessibility // This assumes that *all* CIDFonts use a /ToUnicode mapping Typeface tf = getTypeface(fontName); @@ -981,7 +984,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { textUtil.setStartPosition(rx, bl); textUtil.setSpacing(text.getTextLetterSpaceAdjust(), text.getTextWordSpaceAdjust()); super.renderText(text); - + textUtil.setPtr(ptr); // used for accessibility textUtil.flush(); renderTextDecoration(tf, size, text, bl, rx); } @@ -1054,15 +1057,24 @@ public class IFRenderer extends AbstractPathOrientedRenderer { private static final int INITIAL_BUFFER_SIZE = 16; private int[] dx = new int[INITIAL_BUFFER_SIZE]; private int lastDXPos = 0; - private StringBuffer text = new StringBuffer(); + private final StringBuffer text = new StringBuffer(); private int startx, starty; private int tls, tws; - private boolean combined = false; + private final boolean combined = false; + private String ptr = null; // used for accessibility void addChar(char ch) { text.append(ch); } + /** + * used for accessibility + * @param inPtr to be stored + */ + public void setPtr(String inPtr) { + ptr = inPtr; + } + void adjust(int adjust) { if (adjust != 0) { int idx = text.length(); @@ -1105,9 +1117,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer { System.arraycopy(dx, 0, effDX, 0, size); } if (combined) { - painter.drawText(startx, starty, 0, 0, effDX, text.toString()); + painter.drawText(startx, starty, 0, 0, effDX, text.toString(), ptr); } else { - painter.drawText(startx, starty, tls, tws, effDX, text.toString()); + painter.drawText(startx, starty, tls, tws, effDX, text.toString(), ptr); } } catch (IFException e) { handleIFException(e); @@ -1118,12 +1130,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - public void renderImage(Image image, Rectangle2D pos) { - drawImage(image.getURL(), pos, image.getForeignAttributes()); + public void renderImage(Image image, Rectangle2D pos, String ptr) { + drawImage(image.getURL(), pos, image.getForeignAttributes(), ptr); } /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { Rectangle posInt = new Rectangle( currentIPPosition + (int)pos.getX(), currentBPPosition + (int)pos.getY(), @@ -1132,7 +1144,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { uri = URISpecification.getURL(uri); try { establishForeignAttributes(foreignAttributes); - painter.drawImage(uri, posInt); + painter.drawImage(uri, posInt, ptr); resetForeignAttributes(); } catch (IFException ife) { handleIFException(ife); @@ -1140,7 +1152,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + public void renderForeignObject(ForeignObject fo, Rectangle2D pos, String ptr) { endTextObject(); Rectangle posInt = new Rectangle( currentIPPosition + (int)pos.getX(), @@ -1150,7 +1162,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { Document doc = fo.getDocument(); try { establishForeignAttributes(fo.getForeignAttributes()); - painter.drawImage(doc, posInt); + painter.drawImage(doc, posInt, ptr); resetForeignAttributes(); } catch (IFException ife) { handleIFException(ife); diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 5076a089f..d7d4a7539 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -25,11 +25,24 @@ import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Map; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + 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; @@ -60,10 +73,46 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler implements IFConstants, IFPainter, IFDocumentNavigationHandler { private IFDocumentHandler mimicHandler; + private int pageSequenceCounter; // used for accessibility + private DocumentBuilder parser = null; // used for accessibility + private Document doc = null; // used for accessibility /** Holds the intermediate format state */ private IFState state; + private static class NamespaceContextImpl implements NamespaceContext { + + public String uri; + public 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; + } + + } + /** * Default constructor. */ @@ -151,8 +200,16 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX, DocumentNavigationExtensionConstants.NAMESPACE); handler.startElement(EL_DOCUMENT); + if (this.getUserAgent().accessibilityEnabled()) { + pageSequenceCounter = 0; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + parser = factory.newDocumentBuilder(); + } } catch (SAXException e) { throw new IFException("SAX error in startDocument()", e); + } catch (ParserConfigurationException pce) { + throw new IFException("Error creating new DocumentBuilder", pce); } } @@ -210,9 +267,33 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); } + handler.startElement(EL_PAGE_SEQUENCE, atts); + if (this.getUserAgent().accessibilityEnabled()) { + if (doc == null) { + doc = parser.parse( + new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); + } + handler.startElement(EL_STRUCTURE_TREE); // add structure tree + String xpathExpr + = "/fo:root/fo:page-sequence[" + Integer.toString(++pageSequenceCounter) + "]/*"; + XPath xpath = XPathFactory.newInstance().newXPath(); + NamespaceContext namespaceContext + = new NamespaceContextImpl("fo", "http://www.w3.org/1999/XSL/Format"); + xpath.setNamespaceContext(namespaceContext); + NodeList nodes = (NodeList)xpath.evaluate(xpathExpr, doc, XPathConstants.NODESET); + 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); + } } catch (SAXException e) { throw new IFException("SAX error in startPageSequence()", e); + } catch (XPathExpressionException e) { + throw new IFException("Error while evaluating XPath expression", e); + } catch (IOException ioe) { + throw new IFException("I/O error while parsing structure tree", ioe); } } @@ -285,6 +366,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void startPageTrailer() throws IFException { try { handler.startElement(EL_PAGE_TRAILER); + commitNavigation(); } catch (SAXException e) { throw new IFException("SAX error in startPageTrailer()", e); } @@ -293,7 +375,6 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void endPageTrailer() throws IFException { try { - commitNavigation(); handler.endElement(EL_PAGE_TRAILER); } catch (SAXException e) { throw new IFException("SAX error in endPageTrailer()", e); @@ -382,7 +463,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { try { AttributesImpl atts = new AttributesImpl(); addAttribute(atts, XLINK_HREF, uri); @@ -391,6 +472,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); + if (ptr != null) { + addAttribute(atts, "ptr", ptr); // used for accessibility + } handler.element(EL_IMAGE, atts); } catch (SAXException e) { throw new IFException("SAX error in startGroup()", e); @@ -409,7 +493,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { try { AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "x", Integer.toString(rect.x)); @@ -417,6 +501,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); + if (ptr != null) { + addAttribute(atts, "ptr", ptr); // used for accessibility + } handler.startElement(EL_IMAGE, atts); new DOM2SAX(handler).writeDocument(doc, true); handler.endElement(EL_IMAGE); @@ -515,7 +602,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text) throws IFException { + int[] dx, String text, String ptr) throws IFException { try { AttributesImpl atts = new AttributesImpl(); XMLUtil.addAttribute(atts, XMLConstants.XML_SPACE, "preserve"); @@ -530,6 +617,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (dx != null) { addAttribute(atts, "dx", IFUtil.toString(dx)); } + if (ptr != null) { + addAttribute(atts, "ptr", ptr); // used for accessibility + } handler.startElement(EL_TEXT, atts); char[] chars = text.toCharArray(); handler.characters(chars, 0, chars.length); diff --git a/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java b/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java index f396fd09e..8a4237af1 100644 --- a/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java +++ b/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java @@ -27,6 +27,7 @@ import org.apache.xmlgraphics.util.XMLizable; public abstract class AbstractAction implements XMLizable { private String id; + private String ptr; // used for accessibility /** * Sets an ID to make the action referencable. @@ -43,7 +44,23 @@ public abstract class AbstractAction implements XMLizable { public String getID() { return this.id; } - + + /** + * Used for accessibility + * @param s representing the ptr + */ + public void setPtr(String s) { + this.ptr = s; + } + + /** + * Used for accessibility + * @return the ptr + */ + public String getPtr() { + return this.ptr; + } + /** * Indicates whether the action has an ID and is therefore referencable. * @return true if the action has an ID diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java index 55c5b8015..da3108973 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DPainter.java +++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java @@ -156,7 +156,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { drawImageUsingURI(uri, rect); } @@ -168,7 +168,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { drawImageUsingDocument(doc, rect); } @@ -208,7 +208,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text, String ptr) throws IFException { g2dState.updateColor(state.getTextColor()); FontTriplet triplet = new FontTriplet( diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 933398125..74c709278 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -875,7 +875,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem ImageFlavor.XML_DOM}; /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { int x = currentIPPosition + (int)Math.round(pos.getX()); int y = currentBPPosition + (int)Math.round(pos.getY()); diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java index da4f6a656..57810fb38 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -154,7 +154,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { drawImageUsingURI(uri, rect); } @@ -176,7 +176,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { drawImageUsingDocument(doc, rect); } @@ -312,8 +312,9 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text, String ptr) throws IFException { + //Note: ptr is ignored as it is only needed for accessibility try { FontTriplet triplet = new FontTriplet( state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); @@ -474,7 +475,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { Java2DPainter painter = new Java2DPainter(g2d, getContext(), parent.getFontInfo(), state); try { - painter.drawText(x, y, letterSpacing, wordSpacing, dx, text); + painter.drawText(x, y, letterSpacing, wordSpacing, dx, text, ""); } catch (IFException e) { //This should never happen with the Java2DPainter throw new RuntimeException("Unexpected error while painting text", e); diff --git a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java index 841dd7e01..2f4379795 100644 --- a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java +++ b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java @@ -49,4 +49,6 @@ public interface PDFConfigurationConstants { * PDF/X profile is active). */ String KEY_DISABLE_SRGB_COLORSPACE = "disable-srgb-colorspace"; + /** PDF Accessibility */ + String ACCESSIBLITY = "accessibility"; } diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 45fb7ec51..750f9a3cf 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -50,6 +50,7 @@ public class PDFContentGenerator { /** the current stream to add PDF commands to */ private PDFStream currentStream; + private boolean accessEnabled; // used for accessibility /** drawing state */ protected PDFPaintingState currentState = null; @@ -63,9 +64,10 @@ public class PDFContentGenerator { * @param document the PDF document * @param out the output stream the PDF document is generated to * @param resourceContext the resource context + * @param accessibilityEnabled indicating if accessibility is enabled or not */ public PDFContentGenerator(PDFDocument document, OutputStream out, - PDFResourceContext resourceContext) { + PDFResourceContext resourceContext, boolean accessibilityEnabled) { this.document = document; this.outputStream = out; this.resourceContext = resourceContext; @@ -78,6 +80,7 @@ public class PDFContentGenerator { }; this.currentState = new PDFPaintingState(); + this.accessEnabled = accessibilityEnabled; } /** @@ -153,6 +156,23 @@ public class PDFContentGenerator { currentStream.add("q\n"); } + /** {@inheritDoc} */ + protected void saveGraphicsState(String structElemType, int sequenceNum) { + endTextObject(); + currentState.save(); + startAccessSequence(structElemType, sequenceNum); + currentStream.add("q\n"); + } + + /** + * Used for accessibility + * @param structElemType Structure Element Type + * @param sequenceNum Sequence number + */ + protected void startAccessSequence(String structElemType, int sequenceNum) { + currentStream.add(structElemType + " <>\nBDC\n"); + } + /** * Restored the graphics state valid before the previous {@code #saveGraphicsState()}. * @param popState true if the state should also be popped, false if only the PDF command @@ -171,6 +191,35 @@ public class PDFContentGenerator { restoreGraphicsState(true); } + /** used for accessibility */ + protected void restoreGraphicsStateAccess() { + endTextObject(); + currentStream.add("Q\n"); + currentStream.add("EMC\n"); + currentState.restore(); + } + + /** + * used for accessibility, separates 2 text elements + * @param mcid of new text element + * @param structElemType of parent of new text element + */ + protected void separateTextElements(int mcid, String structElemType) { + textutil.endTextObject(true); + textutil.beginTextObjectAccess(mcid, structElemType); + } + + /** + * used for accessibility + * separates a text element from fo:leader text element + */ + public void separateTextElementFromLeader() { + if (!textutil.inArtifactMode()) { + textutil.endTextObject(true); + textutil.beginArtifactTextObject(); + } + } + /** Indicates the beginning of a text object. */ protected void beginTextObject() { if (!textutil.isInTextObject()) { @@ -178,10 +227,30 @@ public class PDFContentGenerator { } } + /** + * Accessibility beginTextObject + * @param mcid of text element + * @param structElemType of parent + */ + protected void beginTextObjectAccess(int mcid, String structElemType) { + if (!textutil.isInTextObject()) { + textutil.beginTextObjectAccess(mcid, structElemType); + } + } + + /** + * Accessibility begin of LeaderTextObject + */ + public void beginLeaderTextObject() { + if (!textutil.isInTextObject()) { + textutil.beginArtifactTextObject(); + } + } + /** Indicates the end of a text object. */ protected void endTextObject() { if (textutil.isInTextObject()) { - textutil.endTextObject(); + textutil.endTextObject(accessEnabled); } } @@ -326,5 +395,26 @@ public class PDFContentGenerator { restoreGraphicsState(); } + /** + * Places a previously registered image at a certain place on the page. + * Accessibility version + * @param x X coordinate + * @param y Y coordinate + * @param w width for image + * @param h height for image + * @param xobj the image XObject + * @param structElemType of this image + * @param mcid of this image + */ + public void placeImage(float x, float y, float w, float h, PDFXObject xobj, + String structElemType, int mcid) { + saveGraphicsState(structElemType, mcid); + add(format(w) + " 0 0 " + + format(-h) + " " + + format(x) + " " + + format(y + h) + + " cm\n" + xobj.getName() + " Do\n"); + restoreGraphicsStateAccess(); + } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index b98b15d5e..f7eb3e7b3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -21,9 +21,28 @@ package org.apache.fop.render.pdf; import java.awt.Dimension; import java.awt.geom.AffineTransform; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.xml.sax.SAXException; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -32,11 +51,19 @@ import org.apache.xmlgraphics.xmp.Metadata; import org.apache.fop.apps.MimeConstants; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAnnotList; +import org.apache.fop.pdf.PDFArray; +import org.apache.fop.pdf.PDFDictionary; import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFName; +import org.apache.fop.pdf.PDFNumsArray; +import org.apache.fop.pdf.PDFObject; import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFReference; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; +import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.PDFStructTreeRoot; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; @@ -52,6 +79,70 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** logging instance */ private static Log log = LogFactory.getLog(PDFDocumentHandler.class); + /** the following variables are used for accessibility */ + private int pageSequenceCounter; + private DocumentBuilder parser = null; + private Document doc = null; + private Map structElemType = new HashMap(); + private boolean accessEnabled = false; + private int parentTreeKey = -1; + private int pageLinkCount = 0; + private int mcidKey = -1; + private PDFParentTree parentTree = null; + private Map structTreeMap = new HashMap(); + private List parentTreeList = new java.util.ArrayList(); + + 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; + } + + } + + private static final class ParentTreeEntry { + private final int position; + private final PDFObject object; + private ParentTreeEntry(int p, PDFObject o) { + position = p; + object = o; + } + private int getPosition() { + return position; + } + private PDFObject getPDFObject() { + return object; + } + } + + /** the PDF Document being created */ protected PDFDocument pdfDoc; @@ -79,7 +170,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** Used for bookmarks/outlines. */ protected Map pageReferences = new java.util.HashMap(); - private PDFDocumentNavigationHandler documentNavigationHandler + private final PDFDocumentNavigationHandler documentNavigationHandler = new PDFDocumentNavigationHandler(this); /** @@ -90,7 +181,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public boolean supportsPagesOutOfOrder() { - return true; + return !accessEnabled; } /** {@inheritDoc} */ @@ -123,8 +214,21 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { super.startDocument(); try { this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); + this.accessEnabled = getUserAgent().accessibilityEnabled(); + if (accessEnabled) { + //TODO: make document language variable, see note on wiki page PDF Accessibility + //TODO: and follow-up emails on fop-dev + this.pdfDoc.getRoot().setLanguage("en"); + parentTree = new PDFParentTree(); + pageSequenceCounter = 0; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + parser = factory.newDocumentBuilder(); + } } catch (IOException e) { throw new IFException("I/O error in startDocument()", e); + } catch (ParserConfigurationException pce) { + throw new IFException("Error creating new DocumentBuilder", pce); } } @@ -137,10 +241,34 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { public void endDocument() throws IFException { try { pdfDoc.getResources().addFonts(pdfDoc, fontInfo); - pdfDoc.outputTrailer(this.outputStream); - + if (getUserAgent().accessibilityEnabled()) { + PDFNumsArray nums = parentTree.getNums(); + for (int i = 0; i <= this.parentTreeKey; i++) { + PDFArray tArray = new PDFArray(); + for (int j = 0; j < parentTreeList.size(); j++) { + if (((ParentTreeEntry)parentTreeList.get(j)).getPosition() == i) { + tArray.add(((ParentTreeEntry)parentTreeList.get(j)).getPDFObject()); + } + } + if (tArray.length() == 1) { + nums.put(i, tArray.get(0)); + } else if (tArray.length() > 1) { + nums.put(i, tArray); + } + } + parentTree.setNums(nums); + getStructTreeRoot().addParentTree(parentTree); + pdfDoc.outputTrailer(this.outputStream); + parser = null; + doc = null; + structElemType = null; + parentTree = null; + structTreeMap = null; + parentTreeList = null; + } else { + pdfDoc.outputTrailer(this.outputStream); + } this.pdfDoc = null; - pdfResources = null; this.generator = null; currentContext = null; @@ -151,9 +279,60 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { super.endDocument(); } + private PDFStructTreeRoot getStructTreeRoot() { + return this.pdfDoc.getRoot().getStructTreeRoot(); + } + + /** {@inheritDoc} */ public void startPageSequence(String id) throws IFException { //TODO page sequence title, country and language + + if (getUserAgent().accessibilityEnabled()) { + try { + if (doc == null) { + doc = parser.parse( + new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); + } + PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); + PDFStructElem structElemPart = new PDFStructElem("page-sequence", parent); + this.pdfDoc.assignObjectNumber(structElemPart); + this.pdfDoc.addTrailerObject(structElemPart); + parent.addKid(structElemPart); + + String xpathExpr = "/fo:root/fo:page-sequence[" + + Integer.toString(++pageSequenceCounter) + "]/*"; + XPath xpath = XPathFactory.newInstance().newXPath(); + NamespaceContext namespaceContext = new NamespaceContextImpl("fo", + "http://www.w3.org/1999/XSL/Format"); + xpath.setNamespaceContext(namespaceContext); + + NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, doc, + XPathConstants.NODESET); + + for (int i = 0, n = nodes.getLength(); i < n; i++) { + Node node = nodes.item(i); + if (node.getNodeName().equals("fo:flow") + || node.getNodeName().equals("fo:static-content")) { + PDFStructElem structElemSect = new PDFStructElem( + node.getLocalName(), structElemPart); + this.pdfDoc.assignObjectNumber(structElemSect); + this.pdfDoc.addTrailerObject(structElemSect); + structElemPart.addKid(structElemSect); + NodeList iNodes = node.getChildNodes(); + for (int j = 0, m = iNodes.getLength(); j < m; j++) { + processContent(iNodes.item(j), structElemSect, 1); + } + } + } + } catch (SAXException e) { + throw new IFException("SAX error in startPageSequence()", e); + } catch (XPathExpressionException e) { + throw new IFException("Error while evaluating XPath expression", e); + } catch (IOException ioe) { + throw new IFException("I/O error while parsing structure tree", ioe); + } + } } /** {@inheritDoc} */ @@ -164,22 +343,25 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public void startPage(int index, String name, String pageMasterName, Dimension size) throws IFException { + // used for accessibility + this.parentTreeKey = this.parentTreeKey + this.pageLinkCount + 1; + this.mcidKey = 0; + this.pageLinkCount = 0; + // this.pdfResources = this.pdfDoc.getResources(); this.currentPage = this.pdfDoc.getFactory().makePage( this.pdfResources, (int)Math.round(size.getWidth() / 1000), - (int)Math.round(size.getHeight() / 1000), - index); - //pageReferences.put(new Integer(index)/*page.getKey()*/, currentPage.referencePDF()); - //pvReferences.put(page.getKey(), page); - + (int)Math.round(size.getHeight() / 1000), index, + parentTreeKey); // used for accessibility pdfUtil.generatePageLabel(index, name); currentPageRef = new PageReference(currentPage, size); this.pageReferences.put(new Integer(index), currentPageRef); - this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, this.currentPage); + this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, + this.currentPage, this.accessEnabled); // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, size.height / 1000f); @@ -234,8 +416,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { static final class PageReference { - private PDFReference pageRef; - private Dimension pageDimension; + private final PDFReference pageRef; + private final Dimension pageDimension; private PageReference(PDFPage page, Dimension dim) { this.pageRef = page.makeReference(); @@ -251,4 +433,191 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } } + /** + * Used for accessibility + * @param position in parentTree + * @param o reference of PDFObject to be added to parentTree + */ + void addToParentTree(int position, PDFObject o) { + PDFNumsArray nums = parentTree.getNums(); + nums.put(position, o); + parentTree.setNums(nums); + } + + + /** + * Used for accessibility + * @param position in parentTree + * @param o object to be added to parentTree + */ + void addToTempList(int position, PDFObject o) { + ParentTreeEntry myEntry = new ParentTreeEntry(position, o); + this.parentTreeList.add(myEntry); + } + + + /** + * Return the PDFObject + * @param ptr this is the key + * @return PDFObject referenced with ptr + */ + PDFObject getTrailerObject(String ptr) { + return (PDFObject) this.structTreeMap.get(ptr); + } + + /** + * Return the parent PDFObject referenced by ptr + * @param ptr this is the key + * @return PDFObject parent of PDFObject referenced with ptr + */ + PDFObject getParentTrailerObject(String ptr) { + PDFStructElem tempStructElem = (PDFStructElem) this.structTreeMap.get(ptr); + return tempStructElem.getParentStructElem(); + } + + /** + * Adds a link object as child to StructElem + * @param ptr of PDFStructElem + * @param o PDFLink object + */ + void addLinkToStructElem(String ptr, PDFObject o) { + PDFDictionary dict = new PDFDictionary(); + dict.put("Type", new PDFName("OBJR")); + dict.put("Pg", this.currentPage); + dict.put("Obj", o); + PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); + tempStructElem.addKid(dict); + } + + /** + * Adds a child to StructElem, called from PDFPainter.drawImage + * @param ptr of PDFStructElem + * @param mcid sequence number within page + */ + void addChildToStructElemImage(String ptr, int mcid) { + PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); + tempStructElem.addMCIDKid(mcid); + tempStructElem.addPage(this.currentPage); + if (!tempStructElem.getLevel1()) { + addMeToParent(tempStructElem); + } + } + + /** + * Adds a child to StructElem, called from PDFPainter.drawText + * @param ptr of PDFSturctElem + * @param mcid sequence number within page + */ + void addChildToStructElemText(String ptr, int mcid) { + PDFDictionary dict = new PDFDictionary(); + dict.put("Type", new PDFName("MCR")); + dict.put("Pg", this.currentPage); + dict.put("MCID", mcid); + PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); + tempStructElem.addKid(dict); + if (!tempStructElem.getLevel1()) { + addMeToParent(tempStructElem); + } + } + + /** + * Add child PDFStructElem to parent child elements + * Repeat until level 1 or child already exists + * @param childStructElem to be added + */ + protected void addMeToParent(PDFStructElem childStructElem) { + PDFStructElem parentStructElem = (PDFStructElem) childStructElem.getParentStructElem(); + // test if child already exists or not + if (parentStructElem.addUniqueKid(childStructElem)) { + if (!parentStructElem.getLevel1()) { + addMeToParent(parentStructElem); + } + } + } + + /** + * increment MCID value + */ + void incMCID() { + this.mcidKey++; + } + + /** + * MCID is a sequential number per page + * @return MCID value + */ + int getMCID() { + return this.mcidKey; + } + + /** + * Used for accessibility + * @param ptr pointer into map of all structElems + * @return type of found structElem + */ + String getStructElemType(String ptr) { + return (String) structElemType.get(ptr); + } + + /** + * Used for accessibility + * @param me node being processed + * @param parent parent node in DOM of me + * @param depth depth level in DOM, static-content & flow are 0 + */ + private void processContent(Node me, PDFStructElem parent, int depth) { + String ptr; + Node attr = me.getAttributes().getNamedItem("foi:ptr"); + if (attr != null) { + ptr = attr.getNodeValue(); + } else { + log.error("Accessibility: missing foi:ptr"); + ptr = ""; + } + String s = me.getLocalName(); + PDFStructElem structElem = new PDFStructElem(s, parent); + this.pdfDoc.assignObjectNumber(structElem); + this.pdfDoc.addTrailerObject(structElem); + if (depth == 1) { + parent.addKid(structElem); + structElem.setLevel1(); + } + if (s.equals("external-graphic") || s.equals("instream-foreign-object")) { + Node altTextNode = me.getAttributes().getNamedItem("fox:alt-text"); + if (altTextNode != null) { + structElem.put("Alt", altTextNode.getNodeValue()); + } else { + log.warn("fo:" + s + + " requires an alternative text attribute fox:alt-text for accessibility"); + structElem.put("Alt", "No alternate text specified"); + } + } + // the following map is used e.g. in PDFPainter.drawText + structElemType.put(ptr, structElem.get("S").toString()); + // this map will be used for fast access of the StructElem by ptr + structTreeMap.put(ptr, structElem); + NodeList nodes = me.getChildNodes(); + depth++; + for (int i = 0, n = nodes.getLength(); i < n; i++) { + processContent(nodes.item(i), structElem, depth); + } + } + + /** + * used for accessibility + * @return mcid to be used for next link to be processed + */ + int getPageLinkCountPlusPageParentKey() { + this.pageLinkCount++; + return (this.parentTreeKey + this.pageLinkCount); + } + + /** + * used for accessibility + * @return current parentTreeKey + */ + int getCurrentParentTreeKey() { + return this.parentTreeKey; + } + } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index bc22bb6d2..2f2de2e62 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -42,15 +42,18 @@ import org.apache.fop.render.intermediate.extensions.NamedDestination; import org.apache.fop.render.intermediate.extensions.URIAction; import org.apache.fop.render.pdf.PDFDocumentHandler.PageReference; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + /** * Implementation of the {@link IFDocumentNavigationHandler} interface for PDF output. */ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler { + private static Log log = LogFactory.getLog(PDFDocumentHandler.class); + private final PDFDocumentHandler documentHandler; - private PDFDocumentHandler documentHandler; - - private Map incompleteActions = new java.util.HashMap(); - private Map completeActions = new java.util.HashMap(); + private final Map incompleteActions = new java.util.HashMap(); + private final Map completeActions = new java.util.HashMap(); /** * Default constructor. @@ -111,6 +114,14 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler PDFLink pdfLink = getPDFDoc().getFactory().makeLink( targetRect2D, pdfAction); if (pdfLink != null) { + //accessibility: ptr has a value + String ptr = link.getAction().getPtr(); + if (ptr.length() > 0) { + this.documentHandler.addLinkToStructElem(ptr, pdfLink); + int id = this.documentHandler.getPageLinkCountPlusPageParentKey(); + pdfLink.setStructParent(id); + this.documentHandler.addToParentTree(id, pdfLink ); + } documentHandler.currentPage.addAnnotation(pdfLink); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java index d47d5a439..074a19bec 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java @@ -82,7 +82,17 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler { float y = (float)pos.getY() / 1000f; float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; - generator.placeImage(x, y, w, h, xobj); + if (context.getUserAgent().accessibilityEnabled()) { + String structElemType = pdfContext.getStructElemType(); + if (structElemType.length() > 0) { + int sequenceNum = pdfContext.getSequenceNum(); + generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); + } else { + generator.placeImage(x, y, w, h, xobj); + } + } else { + generator.placeImage(x, y, w, h, xobj); + } } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java index 3e57c7216..728fa0601 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java @@ -83,7 +83,13 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler, ImageHandl float y = (float)pos.getY() / 1000f; float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; - generator.placeImage(x, y, w, h, xobj); + if (context.getUserAgent().accessibilityEnabled()) { + String structElemType = pdfContext.getStructElemType(); + int sequenceNum = pdfContext.getSequenceNum(); + generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); + } else { + generator.placeImage(x, y, w, h, xobj); + } } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index d1b7aa986..40fabbc5b 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -101,8 +101,8 @@ public class PDFImageHandlerSVG implements ImageHandler { float w = (float)ctx.getDocumentSize().getWidth() * 1000f; float h = (float)ctx.getDocumentSize().getHeight() * 1000f; - float sx = pos.width / (float)w; - float sy = pos.height / (float)h; + float sx = pos.width / w; + float sy = pos.height / h; //Scaling and translation for the bounding box of the image AffineTransform scaling = new AffineTransform( @@ -121,6 +121,11 @@ public class PDFImageHandlerSVG implements ImageHandler { */ generator.comment("SVG setup"); generator.saveGraphicsState(); + if (context.getUserAgent().accessibilityEnabled()) { + String structElemType = pdfContext.getStructElemType(); + int sequenceNum = pdfContext.getSequenceNum(); + generator.startAccessSequence(structElemType, sequenceNum); + } generator.setColor(Color.black, false); generator.setColor(Color.black, true); @@ -168,7 +173,11 @@ public class PDFImageHandlerSVG implements ImageHandler { eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI()); } generator.getState().restore(); - generator.restoreGraphicsState(); + if (context.getUserAgent().accessibilityEnabled()) { + generator.restoreGraphicsStateAccess(); + } else { + generator.restoreGraphicsState(); + } generator.comment("SVG end"); } diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index fa00fd7b4..b87569ed3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -59,12 +59,18 @@ public class PDFPainter extends AbstractIFPainter { /** logging instance */ private static Log log = LogFactory.getLog(PDFPainter.class); - private PDFDocumentHandler documentHandler; + private final PDFDocumentHandler documentHandler; /** The current content generator */ protected PDFContentGenerator generator; - private PDFBorderPainter borderPainter; + private final PDFBorderPainter borderPainter; + + private boolean accessEnabled = false; + + private int mcid; // used for accessibility + + private String structElemType; // used for accessibility /** * Default constructor. @@ -76,6 +82,7 @@ public class PDFPainter extends AbstractIFPainter { this.generator = documentHandler.generator; this.borderPainter = new PDFBorderPainter(this.generator); this.state = IFState.create(); + accessEnabled = this.getUserAgent().accessibilityEnabled(); } /** {@inheritDoc} */ @@ -122,15 +129,50 @@ public class PDFPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) + throws IFException { PDFXObject xobject = getPDFDoc().getXObject(uri); if (xobject != null) { - placeImage(rect, xobject); + if (accessEnabled && ptr.length() > 0) { + mcid = this.documentHandler.getMCID(); + mcid++; // fix for Acro Checker + this.documentHandler.incMCID(); // simulating a parent text element + structElemType = this.documentHandler.getStructElemType(ptr); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getParentTrailerObject(ptr)); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getTrailerObject(ptr)); + placeImageAccess(rect, xobject); + this.documentHandler.addChildToStructElemImage(ptr, mcid); + this.documentHandler.incMCID(); + } else { + placeImage(rect, xobject); + } return; } - - drawImageUsingURI(uri, rect); - + if (accessEnabled && ptr.length() > 0) { + mcid = this.documentHandler.getMCID(); + mcid++; // fix for Acro Checker + this.documentHandler.incMCID(); // simulating a parent text element + structElemType = this.documentHandler.getStructElemType(ptr); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getParentTrailerObject(ptr)); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getTrailerObject(ptr)); + //PDFRenderingContext pdfContext = new PDFRenderingContext( + // getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); + //pdfContext.setMCID(mcid); + //pdfContext.setStructElemType(structElemType); + drawImageUsingURI(uri, rect); + this.documentHandler.addChildToStructElemImage(ptr, mcid); + this.documentHandler.incMCID(); + } else { + drawImageUsingURI(uri, rect); + } flushPDFDoc(); } @@ -138,6 +180,8 @@ public class PDFPainter extends AbstractIFPainter { protected RenderingContext createRenderingContext() { PDFRenderingContext pdfContext = new PDFRenderingContext( getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); + pdfContext.setMCID(mcid); + pdfContext.setStructElemType(structElemType); return pdfContext; } @@ -158,11 +202,43 @@ public class PDFPainter extends AbstractIFPainter { + " cm " + xobj.getName() + " Do\n"); generator.restoreGraphicsState(); } + /** + * Places a previously registered image at a certain place on the page - Accessibility version + * @param x X coordinate + * @param y Y coordinate + * @param w width for image + * @param h height for image + * @param xobj the image XObject + */ + private void placeImageAccess(Rectangle rect, PDFXObject xobj) { + generator.saveGraphicsState(structElemType, mcid); + generator.add(format(rect.width) + " 0 0 " + + format(-rect.height) + " " + + format(rect.x) + " " + + format(rect.y + rect.height ) + + " cm " + xobj.getName() + " Do\n"); + generator.restoreGraphicsStateAccess(); + } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { - drawImageUsingDocument(doc, rect); - + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + if (accessEnabled && ptr.length() > 0) { + mcid = this.documentHandler.getMCID(); + mcid++; // fix for Acro Checker + this.documentHandler.incMCID(); // simulating a parent text element + structElemType = this.documentHandler.getStructElemType(ptr); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getParentTrailerObject(ptr)); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getTrailerObject(ptr)); + drawImageUsingDocument(doc, rect); + this.documentHandler.addChildToStructElemImage(ptr, mcid); + this.documentHandler.incMCID(); + } else { + drawImageUsingDocument(doc, rect); + } flushPDFDoc(); } @@ -253,10 +329,38 @@ public class PDFPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, + String text, String ptr) throws IFException { - generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObject(); + if (accessEnabled ) { + int mcId; + String structElType = ""; + if (ptr != null && ptr.length() > 0) { + mcId = this.documentHandler.getMCID(); + this.documentHandler.addToTempList( + this.documentHandler.getCurrentParentTreeKey(), + this.documentHandler.getTrailerObject(ptr)); + structElType = this.documentHandler.getStructElemType(ptr); + if (generator.getTextUtil().isInTextObject()) { + generator.separateTextElements(mcId, structElType); + } + generator.updateColor(state.getTextColor(), true, null); + generator.beginTextObjectAccess(mcId, structElType); + this.documentHandler.addChildToStructElemText(ptr, mcId); + this.documentHandler.incMCID(); + } else { + // + if (generator.getTextUtil().isInTextObject()) { + generator.separateTextElementFromLeader(); + } + generator.updateColor(state.getTextColor(), true, null); + generator.beginLeaderTextObject(); + } + } else { + generator.updateColor(state.getTextColor(), true, null); + generator.beginTextObject(); + } + FontTriplet triplet = new FontTriplet( state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); //TODO Ignored: state.getFontVariant() @@ -277,7 +381,7 @@ public class PDFPainter extends AbstractIFPainter { PDFTextUtil textutil = generator.getTextUtil(); textutil.updateTf(fontKey, fontSize, tf.isMultiByte()); - generator.updateCharacterSpacing((float)letterSpacing / 1000f); + generator.updateCharacterSpacing(letterSpacing / 1000f); textutil.writeTextMatrix(new AffineTransform(1, 0, 0, -1, x / 1000f, y / 1000f)); int l = text.length(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index c40c94fc4..c6b4d4977 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -461,7 +461,8 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf double h = bounds.getHeight(); pageHeight = (int) h; - this.generator = new PDFContentGenerator(this.pdfDoc, this.ostream, this.currentPage); + this.generator = new PDFContentGenerator(this.pdfDoc, this.ostream, this.currentPage, + false); this.borderPainter = new PDFBorderPainter(this.generator); // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFRenderer's @@ -1073,7 +1074,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } /** {@inheritDoc} */ - protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes, String ptr) { endTextObject(); putImage(url, pos, foreignAttributes); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java index 98b0c8203..f82019b4a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java @@ -34,6 +34,11 @@ public class PDFRenderingContext extends AbstractRenderingContext { private PDFContentGenerator generator; private FontInfo fontInfo; private PDFPage page; + /** Temp. val. for accessibility, used in PDFImageHandlerRenderedImage */ + private String structElemType = ""; + + /** Temp. val. for accessibility, used in PDFImageHandlerRenderedImage */ + private int mcid = -1; /** * Main constructor. @@ -79,4 +84,35 @@ public class PDFRenderingContext extends AbstractRenderingContext { return this.fontInfo; } + /** + * Used for accessibility, used in PDFPainter.drawImage + * @param value to be stored + */ + public void setMCID(int value) { + mcid = value; + } + + /** + * Used for accessibility + * @return mcid + */ + public int getSequenceNum() { + return mcid; + } + + /** + * Used for accessibility + * @param s the type of the structure element + */ + public void setStructElemType(String s) { + structElemType = s; + } + + /** + * Used for accessibility + * @return the type of the structure element + */ + public String getStructElemType() { + return structElemType; + } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 2e3c83126..8d9536bff 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -52,6 +52,8 @@ import org.apache.fop.pdf.PDFMetadata; import org.apache.fop.pdf.PDFNumsArray; import org.apache.fop.pdf.PDFOutputIntent; import org.apache.fop.pdf.PDFPageLabels; +import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.PDFStructTreeRoot; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.util.ColorProfileUtil; @@ -75,6 +77,9 @@ class PDFRenderingUtil implements PDFConfigurationConstants { /** the PDF/X mode (Default: disabled) */ protected PDFXMode pdfXMode = PDFXMode.DISABLED; + /** the accessibility mode (Default: false=disabled) */ + protected boolean accessibility = false; + /** the (optional) encryption parameters */ protected PDFEncryptionParams encryptionParams; @@ -169,6 +174,12 @@ class PDFRenderingUtil implements PDFConfigurationConstants { if (s != null) { this.outputProfileURI = s; } + // used for accessibility + setting = userAgent.getRendererOptions().get(ACCESSIBLITY); + if (setting != null) { + this.accessibility = booleanValueOf(setting); + } + setting = userAgent.getRendererOptions().get(KEY_DISABLE_SRGB_COLORSPACE); if (setting != null) { this.disableSRGBColorSpace = booleanValueOf(setting); @@ -384,6 +395,16 @@ class PDFRenderingUtil implements PDFConfigurationConstants { log.debug("PDF/A is active. Conformance Level: " + pdfAMode); addPDFA1OutputIntent(); } + if (this.accessibility) { + this.pdfDoc.getRoot().makeTagged(); + log.info("Accessibility is enabled"); + PDFStructTreeRoot structTreeRoot = this.pdfDoc.getFactory().makeStructTreeRoot(); + this.pdfDoc.getRoot().setStructTreeRoot(structTreeRoot); + PDFStructElem structElemDocument = new PDFStructElem("root", structTreeRoot); + this.pdfDoc.assignObjectNumber(structElemDocument); + this.pdfDoc.addTrailerObject(structElemDocument); + structTreeRoot.addKid(structElemDocument); + } return this.pdfDoc; } diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java index cb88f4670..807bf50b4 100644 --- a/src/java/org/apache/fop/render/ps/PSPainter.java +++ b/src/java/org/apache/fop/render/ps/PSPainter.java @@ -176,7 +176,7 @@ public class PSPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { + public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { try { endTextObject(); } catch (IOException ioe) { @@ -186,7 +186,7 @@ public class PSPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect) throws IFException { + public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { try { endTextObject(); } catch (IOException ioe) { @@ -338,7 +338,7 @@ public class PSPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text) throws IFException { + int[] dx, String text, String ptr) throws IFException { try { //Note: dy is currently ignored PSGenerator generator = getGenerator(); diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 19fcd8af8..5b918156b 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -345,7 +345,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer } /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { endTextObject(); int x = currentIPPosition + (int)Math.round(pos.getX()); int y = currentBPPosition + (int)Math.round(pos.getY()); @@ -1233,7 +1233,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer * {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { - drawImage(image.getURL(), pos, image.getForeignAttributes()); + drawImage(image.getURL(), pos, image.getForeignAttributes(), ""); } /** diff --git a/src/java/org/apache/fop/render/txt/TXTRenderer.java b/src/java/org/apache/fop/render/txt/TXTRenderer.java index 575f1232f..2170a67d2 100644 --- a/src/java/org/apache/fop/render/txt/TXTRenderer.java +++ b/src/java/org/apache/fop/render/txt/TXTRenderer.java @@ -443,7 +443,7 @@ public class TXTRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes, String ptr) { //No images are painted here } diff --git a/src/java/org/apache/fop/util/DOM2SAX.java b/src/java/org/apache/fop/util/DOM2SAX.java index 839cf107f..b9021ed3a 100644 --- a/src/java/org/apache/fop/util/DOM2SAX.java +++ b/src/java/org/apache/fop/util/DOM2SAX.java @@ -77,6 +77,15 @@ public class DOM2SAX { contentHandler.endDocument(); } } + + /** + * Writes the given fragment using the given ContentHandler. + * @param node DOM node + * @throws SAXException In case of a problem while writing XML + */ + public void writeFragment(Node node) throws SAXException { + writeNode(node); + } /** * Begin the scope of namespace prefix. Forward the event to the SAX handler -- cgit v1.2.3 From 863f9e143a65ce4f4335d9dcde55bbbb90bc4502 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 20 Feb 2009 14:18:58 +0000 Subject: JavaBeanified FOUserAgent.accessibilityEnabled(). Moved accessibility initialization out of PDFRenderingUtil because PDFRenderer doesn't support accessibility and both the new and old implementation use this class. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@746248 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/apps/FOUserAgent.java | 6 +++--- src/java/org/apache/fop/apps/Fop.java | 2 +- .../fop/render/intermediate/IFSerializer.java | 4 ++-- .../apache/fop/render/pdf/PDFDocumentHandler.java | 16 +++++++++++++--- .../fop/render/pdf/PDFImageHandlerRawJPEG.java | 2 +- .../render/pdf/PDFImageHandlerRenderedImage.java | 2 +- .../apache/fop/render/pdf/PDFImageHandlerSVG.java | 4 ++-- src/java/org/apache/fop/render/pdf/PDFPainter.java | 2 +- .../org/apache/fop/render/pdf/PDFRenderingUtil.java | 21 --------------------- 9 files changed, 24 insertions(+), 35 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 1e0e3fb86..c0c14de62 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -623,10 +623,10 @@ public class FOUserAgent { } /** - * check if accessibility is enabled - * @return boolean + * Check if accessibility is enabled. + * @return true if accessibility is enabled */ - public boolean accessibilityEnabled() { + public boolean isAccessibilityEnabled() { Boolean enabled = (Boolean)this.getRendererOptions().get("accessibility"); if (enabled != null) { return enabled.booleanValue(); diff --git a/src/java/org/apache/fop/apps/Fop.java b/src/java/org/apache/fop/apps/Fop.java index e5927fdba..9dfa70325 100644 --- a/src/java/org/apache/fop/apps/Fop.java +++ b/src/java/org/apache/fop/apps/Fop.java @@ -111,7 +111,7 @@ public class Fop { if (foTreeBuilder == null) { createDefaultHandler(); } - if (this.foUserAgent.accessibilityEnabled()) { + if (this.foUserAgent.isAccessibilityEnabled()) { return AccessibilityUtil.decorateDefaultHandler(this.foTreeBuilder, foUserAgent); } else { return this.foTreeBuilder; diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index d7d4a7539..248492a96 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -200,7 +200,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX, DocumentNavigationExtensionConstants.NAMESPACE); handler.startElement(EL_DOCUMENT); - if (this.getUserAgent().accessibilityEnabled()) { + if (this.getUserAgent().isAccessibilityEnabled()) { pageSequenceCounter = 0; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); @@ -269,7 +269,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } handler.startElement(EL_PAGE_SEQUENCE, atts); - if (this.getUserAgent().accessibilityEnabled()) { + if (this.getUserAgent().isAccessibilityEnabled()) { if (doc == null) { doc = parser.parse( new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index f7eb3e7b3..3e27fce97 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -214,11 +214,21 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { super.startDocument(); try { this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); - this.accessEnabled = getUserAgent().accessibilityEnabled(); + this.accessEnabled = getUserAgent().isAccessibilityEnabled(); if (accessEnabled) { + this.pdfDoc.getRoot().makeTagged(); + log.info("Accessibility is enabled"); + PDFStructTreeRoot structTreeRoot = this.pdfDoc.getFactory().makeStructTreeRoot(); + this.pdfDoc.getRoot().setStructTreeRoot(structTreeRoot); + PDFStructElem structElemDocument = new PDFStructElem("root", structTreeRoot); + this.pdfDoc.assignObjectNumber(structElemDocument); + this.pdfDoc.addTrailerObject(structElemDocument); + structTreeRoot.addKid(structElemDocument); + //TODO: make document language variable, see note on wiki page PDF Accessibility //TODO: and follow-up emails on fop-dev this.pdfDoc.getRoot().setLanguage("en"); + parentTree = new PDFParentTree(); pageSequenceCounter = 0; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -241,7 +251,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { public void endDocument() throws IFException { try { pdfDoc.getResources().addFonts(pdfDoc, fontInfo); - if (getUserAgent().accessibilityEnabled()) { + if (getUserAgent().isAccessibilityEnabled()) { PDFNumsArray nums = parentTree.getNums(); for (int i = 0; i <= this.parentTreeKey; i++) { PDFArray tArray = new PDFArray(); @@ -288,7 +298,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { public void startPageSequence(String id) throws IFException { //TODO page sequence title, country and language - if (getUserAgent().accessibilityEnabled()) { + if (getUserAgent().isAccessibilityEnabled()) { try { if (doc == null) { doc = parser.parse( diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java index 074a19bec..925d63bc5 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java @@ -82,7 +82,7 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler { float y = (float)pos.getY() / 1000f; float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; - if (context.getUserAgent().accessibilityEnabled()) { + if (context.getUserAgent().isAccessibilityEnabled()) { String structElemType = pdfContext.getStructElemType(); if (structElemType.length() > 0) { int sequenceNum = pdfContext.getSequenceNum(); diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java index 728fa0601..24d17a2b1 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java @@ -83,7 +83,7 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler, ImageHandl float y = (float)pos.getY() / 1000f; float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; - if (context.getUserAgent().accessibilityEnabled()) { + if (context.getUserAgent().isAccessibilityEnabled()) { String structElemType = pdfContext.getStructElemType(); int sequenceNum = pdfContext.getSequenceNum(); generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index 40fabbc5b..c405a2f2a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -121,7 +121,7 @@ public class PDFImageHandlerSVG implements ImageHandler { */ generator.comment("SVG setup"); generator.saveGraphicsState(); - if (context.getUserAgent().accessibilityEnabled()) { + if (context.getUserAgent().isAccessibilityEnabled()) { String structElemType = pdfContext.getStructElemType(); int sequenceNum = pdfContext.getSequenceNum(); generator.startAccessSequence(structElemType, sequenceNum); @@ -173,7 +173,7 @@ public class PDFImageHandlerSVG implements ImageHandler { eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI()); } generator.getState().restore(); - if (context.getUserAgent().accessibilityEnabled()) { + if (context.getUserAgent().isAccessibilityEnabled()) { generator.restoreGraphicsStateAccess(); } else { generator.restoreGraphicsState(); diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index b87569ed3..3fdfccd2e 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -82,7 +82,7 @@ public class PDFPainter extends AbstractIFPainter { this.generator = documentHandler.generator; this.borderPainter = new PDFBorderPainter(this.generator); this.state = IFState.create(); - accessEnabled = this.getUserAgent().accessibilityEnabled(); + accessEnabled = this.getUserAgent().isAccessibilityEnabled(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 8d9536bff..2e3c83126 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -52,8 +52,6 @@ import org.apache.fop.pdf.PDFMetadata; import org.apache.fop.pdf.PDFNumsArray; import org.apache.fop.pdf.PDFOutputIntent; import org.apache.fop.pdf.PDFPageLabels; -import org.apache.fop.pdf.PDFStructElem; -import org.apache.fop.pdf.PDFStructTreeRoot; import org.apache.fop.pdf.PDFXMode; import org.apache.fop.util.ColorProfileUtil; @@ -77,9 +75,6 @@ class PDFRenderingUtil implements PDFConfigurationConstants { /** the PDF/X mode (Default: disabled) */ protected PDFXMode pdfXMode = PDFXMode.DISABLED; - /** the accessibility mode (Default: false=disabled) */ - protected boolean accessibility = false; - /** the (optional) encryption parameters */ protected PDFEncryptionParams encryptionParams; @@ -174,12 +169,6 @@ class PDFRenderingUtil implements PDFConfigurationConstants { if (s != null) { this.outputProfileURI = s; } - // used for accessibility - setting = userAgent.getRendererOptions().get(ACCESSIBLITY); - if (setting != null) { - this.accessibility = booleanValueOf(setting); - } - setting = userAgent.getRendererOptions().get(KEY_DISABLE_SRGB_COLORSPACE); if (setting != null) { this.disableSRGBColorSpace = booleanValueOf(setting); @@ -395,16 +384,6 @@ class PDFRenderingUtil implements PDFConfigurationConstants { log.debug("PDF/A is active. Conformance Level: " + pdfAMode); addPDFA1OutputIntent(); } - if (this.accessibility) { - this.pdfDoc.getRoot().makeTagged(); - log.info("Accessibility is enabled"); - PDFStructTreeRoot structTreeRoot = this.pdfDoc.getFactory().makeStructTreeRoot(); - this.pdfDoc.getRoot().setStructTreeRoot(structTreeRoot); - PDFStructElem structElemDocument = new PDFStructElem("root", structTreeRoot); - this.pdfDoc.assignObjectNumber(structElemDocument); - this.pdfDoc.addTrailerObject(structElemDocument); - structTreeRoot.addKid(structElemDocument); - } return this.pdfDoc; } -- cgit v1.2.3 From 5a2e8bf69db14f444854233333b3b3918e0061b1 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 9 Apr 2009 07:44:59 +0000 Subject: Bugzilla #46974: Possible NPE fixed in PDFImageHandlerRawJPEG.handleImage(). Submitted by: Jost Klopfstein git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@763549 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java index 925d63bc5..fe3a00aa8 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java @@ -84,7 +84,7 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler { float h = (float)pos.getHeight() / 1000f; if (context.getUserAgent().isAccessibilityEnabled()) { String structElemType = pdfContext.getStructElemType(); - if (structElemType.length() > 0) { + if (structElemType != null && structElemType.length() > 0) { int sequenceNum = pdfContext.getSequenceNum(); generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); } else { -- cgit v1.2.3 From 59f151eaef8c4b0dce993489b4259c86258cb6d0 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 14:20:28 +0000 Subject: Strange, this change didn't get merged over. Not sure why. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764785 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/intermediate/IFUtil.java | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFUtil.java b/src/java/org/apache/fop/render/intermediate/IFUtil.java index 2654eb2a3..437648bcc 100644 --- a/src/java/org/apache/fop/render/intermediate/IFUtil.java +++ b/src/java/org/apache/fop/render/intermediate/IFUtil.java @@ -153,6 +153,13 @@ public class IFUtil { if (fontInfo == null) { fontInfo = new FontInfo(); } + if (documentHandler instanceof IFSerializer) { + IFSerializer serializer = (IFSerializer)documentHandler; + if (serializer.getMimickedDocumentHandler() != null) { + //Use the mimicked document handler's configurator to set up fonts + documentHandler = serializer.getMimickedDocumentHandler(); + } + } IFDocumentHandlerConfigurator configurator = documentHandler.getConfigurator(); if (configurator != null) { configurator.setupFontInfo(documentHandler, fontInfo); @@ -172,4 +179,21 @@ public class IFUtil { setupFonts(documentHandler, null); } + /** + * Returns the MIME type of the output format that the given document handler is supposed to + * handle. If the document handler is an {@link IFSerializer} it returns the MIME type of the + * document handler it is mimicking. + * @param documentHandler the document handler + * @return the effective MIME type + */ + public static String getEffectiveMIMEType(IFDocumentHandler documentHandler) { + if (documentHandler instanceof IFSerializer) { + IFDocumentHandler mimic = ((IFSerializer)documentHandler).getMimickedDocumentHandler(); + if (mimic != null) { + return mimic.getMimeType(); + } + } + return documentHandler.getMimeType(); + } + } -- cgit v1.2.3 From df97c24632b56eed65206ee97301605ab7f91bcc Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 14:40:50 +0000 Subject: Fix test case: fox:alt was renamed to fox:alt-text. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764798 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fo/FOPropertyMapping.java | 2 +- test/layoutengine/standard-testcases/foreign-attributes.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index d214dee99..0096f881f 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -2521,7 +2521,7 @@ public final class FOPropertyMapping implements Constants { m.setDefault(""); addPropertyMaker("foi:ptr", m); - // fox:alt, used for accessibility + // fox:alt-text, used for accessibility m = new StringProperty.Maker(PR_X_ALT_TEXT); m.setInherited(false); m.setDefault(""); diff --git a/test/layoutengine/standard-testcases/foreign-attributes.xml b/test/layoutengine/standard-testcases/foreign-attributes.xml index 092860765..537f5ca39 100644 --- a/test/layoutengine/standard-testcases/foreign-attributes.xml +++ b/test/layoutengine/standard-testcases/foreign-attributes.xml @@ -32,7 +32,7 @@ - + FOP @@ -43,7 +43,7 @@ - + -- cgit v1.2.3 From 45e74b066f85dc88a36a2385bdfbbef85f766764 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 14:47:43 +0000 Subject: Reverted changes for "ptr" to painter interface as announced in #46705. The pointer value is now provided through the IFContext so only the implementations that support it have to deal with it. Also, the method signature changes in the renderers are now reverted. They are not necessary. Found a few other smaller omissions (IFRenderer, IFSerializer) that didn't seem to have been merged properly from Trunk. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764802 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/AbstractPathOrientedRenderer.java | 6 +- .../org/apache/fop/render/AbstractRenderer.java | 12 ++-- src/java/org/apache/fop/render/afp/AFPPainter.java | 6 +- .../org/apache/fop/render/afp/AFPRenderer.java | 4 +- .../apache/fop/render/intermediate/IFContext.java | 18 ++++++ .../apache/fop/render/intermediate/IFPainter.java | 9 +-- .../apache/fop/render/intermediate/IFParser.java | 18 +++++- .../apache/fop/render/intermediate/IFRenderer.java | 64 +++++++++++++--------- .../fop/render/intermediate/IFSerializer.java | 11 ++-- .../apache/fop/render/java2d/Java2DPainter.java | 6 +- .../apache/fop/render/java2d/Java2DRenderer.java | 2 +- src/java/org/apache/fop/render/pcl/PCLPainter.java | 9 ++- src/java/org/apache/fop/render/pdf/PDFPainter.java | 18 +++--- .../org/apache/fop/render/pdf/PDFRenderer.java | 2 +- src/java/org/apache/fop/render/ps/PSPainter.java | 6 +- src/java/org/apache/fop/render/ps/PSRenderer.java | 4 +- .../org/apache/fop/render/txt/TXTRenderer.java | 5 +- .../org/apache/fop/render/svg/SVGPainter.java | 9 ++- 18 files changed, 124 insertions(+), 85 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java index 8da4b3973..54f6170db 100644 --- a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -834,10 +834,8 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { * @param url the URI/URL of the image * @param pos the position of the image * @param foreignAttributes an optional Map with foreign attributes, may be null - * @param ptr used for accessibility */ - protected abstract void drawImage(String url, Rectangle2D pos, Map foreignAttributes, - String ptr); + protected abstract void drawImage(String url, Rectangle2D pos, Map foreignAttributes); /** * Draw an image at the indicated location. @@ -845,7 +843,7 @@ public abstract class AbstractPathOrientedRenderer extends PrintRenderer { * @param pos the position of the image */ protected final void drawImage(String url, Rectangle2D pos) { - drawImage(url, pos, null, ""); + drawImage(url, pos, null); } /** diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java index 8f60ace2f..ed7682221 100644 --- a/src/java/org/apache/fop/render/AbstractRenderer.java +++ b/src/java/org/apache/fop/render/AbstractRenderer.java @@ -738,13 +738,11 @@ public abstract class AbstractRenderer currentBPPosition += viewport.getOffset(); Rectangle2D contpos = viewport.getContentPosition(); if (content instanceof Image) { - String ptr = (String) viewport.getTrait(Trait.PTR); - renderImage((Image) content, contpos, ptr); + renderImage((Image) content, contpos); } else if (content instanceof Container) { renderContainer((Container) content); } else if (content instanceof ForeignObject) { - String ptr = (String) viewport.getTrait(Trait.PTR); - renderForeignObject((ForeignObject) content, contpos, ptr); + renderForeignObject((ForeignObject) content, contpos); } else if (content instanceof InlineBlockParent) { renderInlineBlockParent((InlineBlockParent) content); } @@ -757,10 +755,9 @@ public abstract class AbstractRenderer * * @param image The image * @param pos The target position of the image - * @param ptr used for accessibility * (todo) Make renderImage() protected */ - public void renderImage(Image image, Rectangle2D pos, String ptr) { + public void renderImage(Image image, Rectangle2D pos) { // Default: do nothing. // Some renderers (ex. Text) don't support images. } @@ -784,10 +781,9 @@ public abstract class AbstractRenderer * * @param fo The foreign object area * @param pos The target position of the foreign object - * @param ptr used for accessibility * (todo) Make renderForeignObject() protected */ - protected void renderForeignObject(ForeignObject fo, Rectangle2D pos, String ptr) { + protected void renderForeignObject(ForeignObject fo, Rectangle2D pos) { // Default: do nothing. // Some renderers (ex. Text) don't support foreign objects. } diff --git a/src/java/org/apache/fop/render/afp/AFPPainter.java b/src/java/org/apache/fop/render/afp/AFPPainter.java index 3efe5cbb4..a92be9d6e 100644 --- a/src/java/org/apache/fop/render/afp/AFPPainter.java +++ b/src/java/org/apache/fop/render/afp/AFPPainter.java @@ -184,7 +184,7 @@ public class AFPPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { String name = documentHandler.getPageSegmentNameFor(uri); if (name != null) { float[] srcPts = {rect.x, rect.y}; @@ -196,7 +196,7 @@ public class AFPPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { drawImageUsingDocument(doc, rect); } @@ -313,7 +313,7 @@ public class AFPPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawText(int x, int y, final int letterSpacing, final int wordSpacing, final int[] dx, - final String text, final String ptr) throws IFException { + final String text) throws IFException { final int fontSize = this.state.getFontSize(); getPaintingState().setFontSize(fontSize); diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index 7e34d361c..94fd05dc8 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -395,7 +395,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE }; /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { + public void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { uri = URISpecification.getURL(uri); paintingState.setImageUri(uri); @@ -526,7 +526,7 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust /** {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { - drawImage(image.getURL(), pos, image.getForeignAttributes(),""); + drawImage(image.getURL(), pos, image.getForeignAttributes()); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index b05db1369..30989d04f 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -43,6 +43,8 @@ public class IFContext { /** foreign attributes: Map */ private Map foreignAttributes = Collections.EMPTY_MAP; + private String structurePointer; + /** * Main constructor. * @param ua the user agent @@ -108,4 +110,20 @@ public class IFContext { setForeignAttributes(null); } + public void setStructurePointer(String ptr) { + this.structurePointer = ptr; + } + + public void resetStructurePointer() { + setStructurePointer(null); + } + + public String getStructurePointer() { + return this.structurePointer; + } + + public boolean hasStructurePointer() { + return (this.structurePointer != null) && (structurePointer.length() > 0); + } + } diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java index 163fe16a1..6369b0251 100644 --- a/src/java/org/apache/fop/render/intermediate/IFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java @@ -153,11 +153,10 @@ public interface IFPainter { * @param wordSpacing additional spacing between words (may be 0) * @param dx an array of adjustment values for each character in X-direction (may be null) * @param text the text - * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text, String ptr) throws IFException; + int[] dx, String text) throws IFException; /** * Restricts the current clipping region with the given rectangle. @@ -206,20 +205,18 @@ public interface IFPainter { * an fo:external-graphic in XSL-FO. * @param uri the image's URI * @param rect the rectangle in which the image shall be painted - * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ - void drawImage(String uri, Rectangle rect, String ptr) throws IFException; + void drawImage(String uri, Rectangle rect) throws IFException; /** * Draws an image (represented by a DOM document) inside a given rectangle. This is the * equivalent to an fo:instream-foreign-object in XSL-FO. * @param doc the DOM document containing the foreign object * @param rect the rectangle in which the image shall be painted - * @param ptr used for accessibility * @throws IFException if an error occurs while handling this event */ - void drawImage(Document doc, Rectangle rect, String ptr) throws IFException; + void drawImage(Document doc, Rectangle rect) throws IFException; //Note: For now, all foreign objects are handled as DOM documents. At the moment, all known //implementations use a DOM anyway, so optimizing this to work with SAX wouldn't result in //any performance benefits. The IFRenderer itself has a DOM anyway. Only the IFParser could diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 47e24445c..5dbe6e46c 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -173,6 +173,14 @@ public class IFParser implements IFConstants { documentHandler.getContext().resetForeignAttributes(); } + private void establishStructurePointer(String ptr) { + documentHandler.getContext().setStructurePointer(ptr); + } + + private void resetStructurePointer() { + documentHandler.getContext().resetStructurePointer(); + } + /** {@inheritDoc} */ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { @@ -482,7 +490,9 @@ public class IFParser implements IFConstants { int wordSpacing = (s != null ? Integer.parseInt(s) : 0); int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx"); String ptr = lastAttributes.getValue("ptr"); // used for accessibility - painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString(), ptr); + establishStructurePointer(ptr); + painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString()); + resetStructurePointer(); } public boolean ignoreCharacters() { @@ -578,9 +588,10 @@ public class IFParser implements IFConstants { Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); String ptr = lastAttributes.getValue("ptr"); // used for accessibility + establishStructurePointer(ptr); if (foreignObject != null) { painter.drawImage(foreignObject, - new Rectangle(x, y, width, height), ptr); + new Rectangle(x, y, width, height)); foreignObject = null; } else { String uri = lastAttributes.getValue( @@ -588,9 +599,10 @@ public class IFParser implements IFConstants { if (uri == null) { throw new IFException("xlink:href is missing on image", null); } - painter.drawImage(uri, new Rectangle(x, y, width, height), ptr); + painter.drawImage(uri, new Rectangle(x, y, width, height)); } resetForeignAttributes(); + resetStructurePointer(); inForeignObject = false; } diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 664f1324a..905277f1b 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -53,6 +53,7 @@ import org.apache.fop.Version; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.MimeConstants; import org.apache.fop.area.Area; +import org.apache.fop.area.AreaTreeObject; import org.apache.fop.area.Block; import org.apache.fop.area.BlockViewport; import org.apache.fop.area.BookmarkData; @@ -500,7 +501,10 @@ public class IFRenderer extends AbstractPathOrientedRenderer { documentHandler.endDocumentHeader(); this.inPageSequence = true; } + establishForeignAttributes(pageSequence.getForeignAttributes()); documentHandler.startPageSequence(null); + resetForeignAttributes(); + processExtensionAttachments(pageSequence); } catch (IFException e) { handleIFException(e); } @@ -557,13 +561,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { documentHandler.startPageHeader(); //Add page attachments to page header - if (page.hasExtensionAttachments()) { - for (Iterator iter = page.getExtensionAttachments().iterator(); - iter.hasNext();) { - ExtensionAttachment attachment = (ExtensionAttachment) iter.next(); - this.documentHandler.handleExtensionObject(attachment); - } - } + processExtensionAttachments(page); documentHandler.endPageHeader(); this.painter = documentHandler.startPageContent(); @@ -590,6 +588,16 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } } + private void processExtensionAttachments(AreaTreeObject area) throws IFException { + if (area.hasExtensionAttachments()) { + for (Iterator iter = area.getExtensionAttachments().iterator(); + iter.hasNext();) { + ExtensionAttachment attachment = (ExtensionAttachment) iter.next(); + this.documentHandler.handleExtensionObject(attachment); + } + } + } + private void establishForeignAttributes(Map foreignAttributes) { documentHandler.getContext().setForeignAttributes(foreignAttributes); } @@ -598,6 +606,14 @@ public class IFRenderer extends AbstractPathOrientedRenderer { documentHandler.getContext().resetForeignAttributes(); } + private void establishStructurePointer(String ptr) { + documentHandler.getContext().setStructurePointer(ptr); + } + + private void resetStructurePointer() { + documentHandler.getContext().resetStructurePointer(); + } + /** {@inheritDoc} */ protected void saveGraphicsState() { graphicContextStack.push(graphicContext); @@ -818,17 +834,20 @@ public class IFRenderer extends AbstractPathOrientedRenderer { currentIPPosition = saveIP; currentBPPosition = saveBP; - currentBPPosition += (bv.getAllocBPD()); + currentBPPosition += bv.getAllocBPD(); } viewportDimensionStack.pop(); } /** {@inheritDoc} */ public void renderViewport(Viewport viewport) { + String ptr = (String) viewport.getTrait(Trait.PTR); + establishStructurePointer(ptr); Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD()); viewportDimensionStack.push(dim); super.renderViewport(viewport); viewportDimensionStack.pop(); + resetStructurePointer(); } /** {@inheritDoc} */ @@ -966,6 +985,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { String fontName = getInternalFontNameForArea(text); int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); String ptr = (String)text.getTrait(Trait.PTR); // used for accessibility + establishStructurePointer(ptr); // This assumes that *all* CIDFonts use a /ToUnicode mapping Typeface tf = getTypeface(fontName); @@ -984,9 +1004,10 @@ public class IFRenderer extends AbstractPathOrientedRenderer { textUtil.setStartPosition(rx, bl); textUtil.setSpacing(text.getTextLetterSpaceAdjust(), text.getTextWordSpaceAdjust()); super.renderText(text); - textUtil.setPtr(ptr); // used for accessibility + textUtil.flush(); renderTextDecoration(tf, size, text, bl, rx); + resetStructurePointer(); } /** {@inheritDoc} */ @@ -1061,20 +1082,11 @@ public class IFRenderer extends AbstractPathOrientedRenderer { private int startx, starty; private int tls, tws; private final boolean combined = false; - private String ptr = null; // used for accessibility void addChar(char ch) { text.append(ch); } - /** - * used for accessibility - * @param inPtr to be stored - */ - public void setPtr(String inPtr) { - ptr = inPtr; - } - void adjust(int adjust) { if (adjust != 0) { int idx = text.length(); @@ -1117,9 +1129,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer { System.arraycopy(dx, 0, effDX, 0, size); } if (combined) { - painter.drawText(startx, starty, 0, 0, effDX, text.toString(), ptr); + painter.drawText(startx, starty, 0, 0, effDX, text.toString()); } else { - painter.drawText(startx, starty, tls, tws, effDX, text.toString(), ptr); + painter.drawText(startx, starty, tls, tws, effDX, text.toString()); } } catch (IFException e) { handleIFException(e); @@ -1130,12 +1142,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - public void renderImage(Image image, Rectangle2D pos, String ptr) { - drawImage(image.getURL(), pos, image.getForeignAttributes(), ptr); + public void renderImage(Image image, Rectangle2D pos) { + drawImage(image.getURL(), pos, image.getForeignAttributes()); } /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { Rectangle posInt = new Rectangle( currentIPPosition + (int)pos.getX(), currentBPPosition + (int)pos.getY(), @@ -1144,7 +1156,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { uri = URISpecification.getURL(uri); try { establishForeignAttributes(foreignAttributes); - painter.drawImage(uri, posInt, ptr); + painter.drawImage(uri, posInt); resetForeignAttributes(); } catch (IFException ife) { handleIFException(ife); @@ -1152,7 +1164,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - public void renderForeignObject(ForeignObject fo, Rectangle2D pos, String ptr) { + public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { endTextObject(); Rectangle posInt = new Rectangle( currentIPPosition + (int)pos.getX(), @@ -1162,7 +1174,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { Document doc = fo.getDocument(); try { establishForeignAttributes(fo.getForeignAttributes()); - painter.drawImage(doc, posInt, ptr); + painter.drawImage(doc, posInt); resetForeignAttributes(); } catch (IFException ife) { handleIFException(ife); diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 248492a96..2f5524c2c 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -267,7 +267,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); } - + addForeignAttributes(atts); handler.startElement(EL_PAGE_SEQUENCE, atts); if (this.getUserAgent().isAccessibilityEnabled()) { if (doc == null) { @@ -463,7 +463,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { try { AttributesImpl atts = new AttributesImpl(); addAttribute(atts, XLINK_HREF, uri); @@ -472,6 +472,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); + String ptr = getContext().getStructurePointer(); if (ptr != null) { addAttribute(atts, "ptr", ptr); // used for accessibility } @@ -493,7 +494,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { try { AttributesImpl atts = new AttributesImpl(); addAttribute(atts, "x", Integer.toString(rect.x)); @@ -501,6 +502,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); + String ptr = getContext().getStructurePointer(); if (ptr != null) { addAttribute(atts, "ptr", ptr); // used for accessibility } @@ -602,7 +604,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text, String ptr) throws IFException { + int[] dx, String text) throws IFException { try { AttributesImpl atts = new AttributesImpl(); XMLUtil.addAttribute(atts, XMLConstants.XML_SPACE, "preserve"); @@ -617,6 +619,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (dx != null) { addAttribute(atts, "dx", IFUtil.toString(dx)); } + String ptr = getContext().getStructurePointer(); if (ptr != null) { addAttribute(atts, "ptr", ptr); // used for accessibility } diff --git a/src/java/org/apache/fop/render/java2d/Java2DPainter.java b/src/java/org/apache/fop/render/java2d/Java2DPainter.java index da3108973..55c5b8015 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DPainter.java +++ b/src/java/org/apache/fop/render/java2d/Java2DPainter.java @@ -156,7 +156,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { drawImageUsingURI(uri, rect); } @@ -168,7 +168,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { drawImageUsingDocument(doc, rect); } @@ -208,7 +208,7 @@ public class Java2DPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text, String ptr) + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) throws IFException { g2dState.updateColor(state.getTextColor()); FontTriplet triplet = new FontTriplet( diff --git a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java index 74c709278..933398125 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DRenderer.java +++ b/src/java/org/apache/fop/render/java2d/Java2DRenderer.java @@ -875,7 +875,7 @@ public abstract class Java2DRenderer extends AbstractPathOrientedRenderer implem ImageFlavor.XML_DOM}; /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { int x = currentIPPosition + (int)Math.round(pos.getX()); int y = currentBPPosition + (int)Math.round(pos.getY()); diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java index 57810fb38..da4f6a656 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -154,7 +154,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { drawImageUsingURI(uri, rect); } @@ -176,7 +176,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { drawImageUsingDocument(doc, rect); } @@ -312,9 +312,8 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text, String ptr) + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text) throws IFException { - //Note: ptr is ignored as it is only needed for accessibility try { FontTriplet triplet = new FontTriplet( state.getFontFamily(), state.getFontStyle(), state.getFontWeight()); @@ -475,7 +474,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { Java2DPainter painter = new Java2DPainter(g2d, getContext(), parent.getFontInfo(), state); try { - painter.drawText(x, y, letterSpacing, wordSpacing, dx, text, ""); + painter.drawText(x, y, letterSpacing, wordSpacing, dx, text); } catch (IFException e) { //This should never happen with the Java2DPainter throw new RuntimeException("Unexpected error while painting text", e); diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 3fdfccd2e..3ab32114c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -129,11 +129,12 @@ public class PDFPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) + public void drawImage(String uri, Rectangle rect) throws IFException { PDFXObject xobject = getPDFDoc().getXObject(uri); if (xobject != null) { - if (accessEnabled && ptr.length() > 0) { + if (accessEnabled && getContext().hasStructurePointer()) { + String ptr = getContext().getStructurePointer(); mcid = this.documentHandler.getMCID(); mcid++; // fix for Acro Checker this.documentHandler.incMCID(); // simulating a parent text element @@ -152,7 +153,8 @@ public class PDFPainter extends AbstractIFPainter { } return; } - if (accessEnabled && ptr.length() > 0) { + if (accessEnabled && getContext().hasStructurePointer()) { + String ptr = getContext().getStructurePointer(); mcid = this.documentHandler.getMCID(); mcid++; // fix for Acro Checker this.documentHandler.incMCID(); // simulating a parent text element @@ -221,8 +223,9 @@ public class PDFPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { - if (accessEnabled && ptr.length() > 0) { + public void drawImage(Document doc, Rectangle rect) throws IFException { + if (accessEnabled && getContext().hasStructurePointer()) { + String ptr = getContext().getStructurePointer(); mcid = this.documentHandler.getMCID(); mcid++; // fix for Acro Checker this.documentHandler.incMCID(); // simulating a parent text element @@ -330,9 +333,10 @@ public class PDFPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, - String text, String ptr) + String text) throws IFException { - if (accessEnabled ) { + if (accessEnabled) { + String ptr = getContext().getStructurePointer(); int mcId; String structElType = ""; if (ptr != null && ptr.length() > 0) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index c6b4d4977..2c166f679 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -1074,7 +1074,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } /** {@inheritDoc} */ - protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes, String ptr) { + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { endTextObject(); putImage(url, pos, foreignAttributes); } diff --git a/src/java/org/apache/fop/render/ps/PSPainter.java b/src/java/org/apache/fop/render/ps/PSPainter.java index 807bf50b4..cb88f4670 100644 --- a/src/java/org/apache/fop/render/ps/PSPainter.java +++ b/src/java/org/apache/fop/render/ps/PSPainter.java @@ -176,7 +176,7 @@ public class PSPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { try { endTextObject(); } catch (IOException ioe) { @@ -186,7 +186,7 @@ public class PSPainter extends AbstractIFPainter { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { try { endTextObject(); } catch (IOException ioe) { @@ -338,7 +338,7 @@ public class PSPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawText(int x, int y, int letterSpacing, int wordSpacing, - int[] dx, String text, String ptr) throws IFException { + int[] dx, String text) throws IFException { try { //Note: dy is currently ignored PSGenerator generator = getGenerator(); diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 5b918156b..19fcd8af8 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -345,7 +345,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer } /** {@inheritDoc} */ - protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes, String ptr) { + protected void drawImage(String uri, Rectangle2D pos, Map foreignAttributes) { endTextObject(); int x = currentIPPosition + (int)Math.round(pos.getX()); int y = currentBPPosition + (int)Math.round(pos.getY()); @@ -1233,7 +1233,7 @@ public class PSRenderer extends AbstractPathOrientedRenderer * {@inheritDoc} */ public void renderImage(Image image, Rectangle2D pos) { - drawImage(image.getURL(), pos, image.getForeignAttributes(), ""); + drawImage(image.getURL(), pos, image.getForeignAttributes()); } /** diff --git a/src/java/org/apache/fop/render/txt/TXTRenderer.java b/src/java/org/apache/fop/render/txt/TXTRenderer.java index 2170a67d2..3e2fab230 100644 --- a/src/java/org/apache/fop/render/txt/TXTRenderer.java +++ b/src/java/org/apache/fop/render/txt/TXTRenderer.java @@ -28,6 +28,8 @@ import java.io.OutputStream; import java.util.List; import java.util.Map; +import org.apache.xmlgraphics.util.UnitConv; + import org.apache.fop.apps.FOPException; import org.apache.fop.area.Area; import org.apache.fop.area.CTM; @@ -37,7 +39,6 @@ import org.apache.fop.area.inline.TextArea; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.txt.border.AbstractBorderElement; import org.apache.fop.render.txt.border.BorderManager; -import org.apache.xmlgraphics.util.UnitConv; /** * Renderer that renders areas to plain text. @@ -443,7 +444,7 @@ public class TXTRenderer extends AbstractPathOrientedRenderer { } /** {@inheritDoc} */ - protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes, String ptr) { + protected void drawImage(String url, Rectangle2D pos, Map foreignAttributes) { //No images are painted here } diff --git a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java index cb0547391..c31190eba 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGPainter.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGPainter.java @@ -193,7 +193,7 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants { } /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect, String ptr) throws IFException { + public void drawImage(String uri, Rectangle rect) throws IFException { try { establish(MODE_NORMAL); @@ -243,7 +243,7 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants { } /** {@inheritDoc} */ - public void drawImage(Document doc, Rectangle rect, String ptr) throws IFException { + public void drawImage(Document doc, Rectangle rect) throws IFException { try { establish(MODE_NORMAL); @@ -326,9 +326,8 @@ public class SVGPainter extends AbstractIFPainter implements SVGConstants { /** {@inheritDoc} */ - public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, - String text, String ptr) throws IFException { - //Note: ptr is ignored as it is only needed for accessibility + public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, + String text) throws IFException { try { establish(MODE_TEXT); AttributesImpl atts = new AttributesImpl(); -- cgit v1.2.3 From fb5ad866ddacadeef228e8963cc63f2a0ba15406 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 16:20:31 +0000 Subject: Missing javadocs. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764861 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/intermediate/IFContext.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index 30989d04f..b534cfa56 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -110,18 +110,37 @@ public class IFContext { setForeignAttributes(null); } + /** + * Sets the structure pointer for the following painted marks. This method is used when + * accessibility features are enabled. + * @param ptr the structure pointer + */ public void setStructurePointer(String ptr) { this.structurePointer = ptr; } + /** + * Resets the current structure pointer. + * @see #setStructurePointer(String) + */ public void resetStructurePointer() { setStructurePointer(null); } + /** + * Returns the current structure pointer. + * @return the structure pointer (or null if no pointer is active) + * @see #setStructurePointer(String) + */ public String getStructurePointer() { return this.structurePointer; } + /** + * Indicates whether a structure pointer is available. + * @return true if there's a structure pointer + * @see #setStructurePointer(String) + */ public boolean hasStructurePointer() { return (this.structurePointer != null) && (structurePointer.length() > 0); } -- cgit v1.2.3 From 2b8757bd0c6006859e8a0a5a8e26fa4dd7c34fb1 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 19:16:28 +0000 Subject: Avoid empty "ptr" traits in the area tree. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764926 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java | 11 ++++++----- .../org/apache/fop/layoutmgr/inline/TextLayoutManager.java | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java index e1f7475e9..eef649c97 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java @@ -19,13 +19,14 @@ package org.apache.fop.layoutmgr.inline; +import org.apache.fop.area.LinkResolver; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.InlineArea; import org.apache.fop.datatypes.URISpecification; -import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.fo.Constants; +import org.apache.fop.fo.flow.BasicLink; import org.apache.fop.layoutmgr.PageSequenceLayoutManager; -import org.apache.fop.area.inline.InlineArea; -import org.apache.fop.area.Trait; -import org.apache.fop.area.LinkResolver; +import org.apache.fop.layoutmgr.TraitSetter; /** * LayoutManager for the fo:basic-link formatting object @@ -56,7 +57,7 @@ public class BasicLinkLayoutManager extends InlineLayoutManager { private void setupBasicLinkArea(InlineArea area) { BasicLink fobj = (BasicLink) this.fobj; // internal destinations take precedence: - area.addTrait(Trait.PTR, fobj.getPtr()); // used for accessibility + TraitSetter.addPtr(area, fobj.getPtr()); // used for accessibility if (fobj.hasInternalDestination()) { String idref = fobj.getInternalDestination(); PageSequenceLayoutManager pslm = getPSLM(); diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index 5c24dbfcb..453bf9953 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -506,7 +506,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager { } TraitSetter.addFontTraits(textArea, font); textArea.addTrait(Trait.COLOR, this.foText.getColor()); - textArea.addTrait(Trait.PTR, getPtr()); // used for accessibility + TraitSetter.addPtr(textArea, getPtr()); // used for accessibility TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration()); return textArea; -- cgit v1.2.3 From 04e57174943031a77902eac1436ec8b9fb26f003 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Tue, 14 Apr 2009 19:49:55 +0000 Subject: Enabled parsing support for foreign attributes on page-sequence. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@764935 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/intermediate/IFParser.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 5dbe6e46c..0648b6628 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -360,7 +360,10 @@ public class IFParser implements IFConstants { public void startElement(Attributes attributes) throws IFException { String id = attributes.getValue("id"); + Map foreignAttributes = getForeignAttributes(lastAttributes); + establishForeignAttributes(foreignAttributes); documentHandler.startPageSequence(id); + resetForeignAttributes(); } public void endElement() throws IFException { -- cgit v1.2.3 From 64ed5db8c1fe1132e693faa2fe74156c1f8aa64a Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:06:04 +0000 Subject: Introduced the StructurePointerPropertySet interface to aid with accessing the structure pointer uniformly (similar to BreakPropertySet). Getting null as the pointer in TextLayoutManager should not be a reason for a warning anymore. A null value can simply indicate that the text is part of a leader which is treated as a painting artifact during rendering. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765522 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/fo/flow/AbstractGraphics.java | 6 ++-- .../fop/fo/flow/AbstractPageNumberCitation.java | 10 ++++--- src/java/org/apache/fop/fo/flow/BasicLink.java | 5 ---- src/java/org/apache/fop/fo/flow/Block.java | 10 ++++--- src/java/org/apache/fop/fo/flow/Character.java | 5 ++-- src/java/org/apache/fop/fo/flow/Inline.java | 5 ++-- src/java/org/apache/fop/fo/flow/PageNumber.java | 5 ++-- .../org/apache/fop/fo/flow/table/TableFObj.java | 12 ++++---- .../fo/properties/StructurePointerPropertySet.java | 34 ++++++++++++++++++++++ .../fop/layoutmgr/inline/TextLayoutManager.java | 11 ++++--- 10 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java index 2ed576a32..bd4152295 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java +++ b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java @@ -29,6 +29,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.LengthRangeProperty; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Common base class for the @@ -36,7 +37,8 @@ import org.apache.fop.fo.properties.SpaceProperty; * and * fo:external-graphic flow formatting objects. */ -public abstract class AbstractGraphics extends FObj implements GraphicsProperties { +public abstract class AbstractGraphics extends FObj + implements GraphicsProperties, StructurePointerPropertySet { // The value of properties relevant for fo:instream-foreign-object // and external-graphics. @@ -209,7 +211,7 @@ public abstract class AbstractGraphics extends FObj implements GraphicsPropertie return keepWithPrevious; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } diff --git a/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java index 3554c8e0e..0f4575c5b 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java +++ b/src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java @@ -21,8 +21,8 @@ package org.apache.fop.fo.flow; import java.awt.Color; -import org.xml.sax.Locator; import org.xml.sax.Attributes; +import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; @@ -35,6 +35,7 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Common base class for the @@ -42,7 +43,8 @@ import org.apache.fop.fo.properties.SpaceProperty; * * fo:page-number-citation-last objects. */ -public abstract class AbstractPageNumberCitation extends FObj { +public abstract class AbstractPageNumberCitation extends FObj + implements StructurePointerPropertySet { // The value of properties relevant for fo:page-number-citation(-last). private CommonBorderPaddingBackground commonBorderPaddingBackground; @@ -140,11 +142,11 @@ public abstract class AbstractPageNumberCitation extends FObj { return textDecoration; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } - + /** @return the "alignment-adjust" property */ public Length getAlignmentAdjust() { return alignmentAdjust; diff --git a/src/java/org/apache/fop/fo/flow/BasicLink.java b/src/java/org/apache/fop/fo/flow/BasicLink.java index 2fe0c9a8d..de435f96d 100644 --- a/src/java/org/apache/fop/fo/flow/BasicLink.java +++ b/src/java/org/apache/fop/fo/flow/BasicLink.java @@ -159,11 +159,6 @@ public class BasicLink extends Inline { return this.showDestination; } - /** @return the "foi:ptr" property. */ - public String getPtr() { - return super.getPtr(); - } - /** {@inheritDoc} */ public String getLocalName() { return "basic-link"; diff --git a/src/java/org/apache/fop/fo/flow/Block.java b/src/java/org/apache/fop/fo/flow/Block.java index efcd18b71..e3176464d 100644 --- a/src/java/org/apache/fop/fo/flow/Block.java +++ b/src/java/org/apache/fop/fo/flow/Block.java @@ -21,6 +21,8 @@ package org.apache.fop.fo.flow; import java.awt.Color; +import org.xml.sax.Locator; + import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.Numeric; @@ -38,13 +40,13 @@ import org.apache.fop.fo.properties.CommonMarginBlock; import org.apache.fop.fo.properties.CommonRelativePosition; import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.SpaceProperty; -import org.xml.sax.Locator; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Class modelling the * fo:block object. */ -public class Block extends FObjMixed implements BreakPropertySet { +public class Block extends FObjMixed implements BreakPropertySet, StructurePointerPropertySet { // used for FO validation private boolean blockOrInlineItemFound = false; @@ -173,11 +175,11 @@ public class Block extends FObjMixed implements BreakPropertySet { return breakAfter; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } - + /** @return the "break-before" property. */ public int getBreakBefore() { return breakBefore; diff --git a/src/java/org/apache/fop/fo/flow/Character.java b/src/java/org/apache/fop/fo/flow/Character.java index 636b2b1c7..7328b5644 100644 --- a/src/java/org/apache/fop/fo/flow/Character.java +++ b/src/java/org/apache/fop/fo/flow/Character.java @@ -38,12 +38,13 @@ import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Class modelling the * fo:character object. */ -public class Character extends FObj { +public class Character extends FObj implements StructurePointerPropertySet { // The value of properties relevant for fo:character. private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonFont commonFont; @@ -209,7 +210,7 @@ public class Character extends FObj { return keepWithPrevious; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } diff --git a/src/java/org/apache/fop/fo/flow/Inline.java b/src/java/org/apache/fop/fo/flow/Inline.java index ea5b49baf..e6e8e9c01 100644 --- a/src/java/org/apache/fop/fo/flow/Inline.java +++ b/src/java/org/apache/fop/fo/flow/Inline.java @@ -26,12 +26,13 @@ import org.apache.fop.datatypes.Length; import org.apache.fop.fo.FONode; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Class modelling the * fo:inline formatting object. */ -public class Inline extends InlineLevel { +public class Inline extends InlineLevel implements StructurePointerPropertySet { // The value of properties relevant for fo:inline. // See also superclass InlineLevel private Length alignmentAdjust; @@ -146,7 +147,7 @@ public class Inline extends InlineLevel { return dominantBaseline; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } diff --git a/src/java/org/apache/fop/fo/flow/PageNumber.java b/src/java/org/apache/fop/fo/flow/PageNumber.java index bb251f44f..34d267a64 100644 --- a/src/java/org/apache/fop/fo/flow/PageNumber.java +++ b/src/java/org/apache/fop/fo/flow/PageNumber.java @@ -34,12 +34,13 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonFont; import org.apache.fop.fo.properties.CommonTextDecoration; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.fo.properties.StructurePointerPropertySet; /** * Class modelling the * fo:page-number object. */ -public class PageNumber extends FObj { +public class PageNumber extends FObj implements StructurePointerPropertySet { // The value of properties relevant for fo:page-number. private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonFont commonFont; @@ -167,7 +168,7 @@ public class PageNumber extends FObj { return lineHeight; } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } diff --git a/src/java/org/apache/fop/fo/flow/table/TableFObj.java b/src/java/org/apache/fop/fo/flow/table/TableFObj.java index 96b3769a3..ab8676cb3 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java @@ -19,6 +19,9 @@ package org.apache.fop.fo.flow.table; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; + import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Numeric; import org.apache.fop.datatypes.ValidationPercentBaseContext; @@ -33,14 +36,13 @@ import org.apache.fop.fo.properties.EnumProperty; import org.apache.fop.fo.properties.NumberProperty; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.PropertyMaker; +import org.apache.fop.fo.properties.StructurePointerPropertySet; import org.apache.fop.layoutmgr.table.CollapsingBorderModel; -import org.xml.sax.Locator; -import org.xml.sax.Attributes; /** * Common base class for table-related FOs */ -public abstract class TableFObj extends FObj { +public abstract class TableFObj extends FObj implements StructurePointerPropertySet { private Numeric borderAfterPrecedence; private Numeric borderBeforePrecedence; @@ -237,11 +239,11 @@ public abstract class TableFObj extends FObj { } } - /** @return the "foi:ptr" property. */ + /** {@inheritDoc} */ public String getPtr() { return ptr; } - + /** * Prepares the borders of this element if the collapsing-border model is in use. * Conflict resolution with parent elements is done where applicable. diff --git a/src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java b/src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java new file mode 100644 index 000000000..5cce2822e --- /dev/null +++ b/src/java/org/apache/fop/fo/properties/StructurePointerPropertySet.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.properties; + +/** + * Defines property access methods for internal structure pointer extension properties. + */ +public interface StructurePointerPropertySet { + + /** + * Returns the value of the "foi:ptr" property, the internal structure pointer used + * for tagged PDF and other formats that support a structure tree in addition to paged content. + * @return the "foi:ptr" property + */ + String getPtr(); + +} diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java index 453bf9953..b8a2b283f 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java @@ -31,6 +31,7 @@ import org.apache.fop.area.inline.TextArea; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FOText; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.properties.StructurePointerPropertySet; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontSelector; import org.apache.fop.layoutmgr.InlineKnuthSequence; @@ -518,13 +519,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager { */ private String getPtr() { FObj fobj = this.parentLM.getFObj(); - if (fobj instanceof org.apache.fop.fo.flow.Block) { - return (((org.apache.fop.fo.flow.Block) fobj).getPtr()); - } else if (fobj instanceof org.apache.fop.fo.flow.Inline) { - return (((org.apache.fop.fo.flow.Inline) fobj).getPtr()); + if (fobj instanceof StructurePointerPropertySet) { + return (((StructurePointerPropertySet) fobj).getPtr()); } else { - log.warn("Accessibility: TLM.getPtr-no Ptr found"); - return ""; + //No structure pointer applicable + return null; } } -- cgit v1.2.3 From 721ef295c32495df02023a22d3c3de13ebb6697f Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:07:23 +0000 Subject: Fixed a possible NPE when intermediate content is parsed and navigation elements are present. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765524 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index 2f2de2e62..2a9a07534 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -25,6 +25,9 @@ import java.awt.geom.Rectangle2D; import java.util.Iterator; import java.util.Map; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.apache.fop.pdf.PDFAction; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFactory; @@ -42,9 +45,6 @@ import org.apache.fop.render.intermediate.extensions.NamedDestination; import org.apache.fop.render.intermediate.extensions.URIAction; import org.apache.fop.render.pdf.PDFDocumentHandler.PageReference; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - /** * Implementation of the {@link IFDocumentNavigationHandler} interface for PDF output. */ @@ -116,7 +116,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler if (pdfLink != null) { //accessibility: ptr has a value String ptr = link.getAction().getPtr(); - if (ptr.length() > 0) { + if (ptr != null && ptr.length() > 0) { this.documentHandler.addLinkToStructElem(ptr, pdfLink); int id = this.documentHandler.getPageLinkCountPlusPageParentKey(); pdfLink.setStructParent(id); -- cgit v1.2.3 From 5a0c020ad1330df3b6c94cef63698344dfbada00 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:10:37 +0000 Subject: Fixed some bugs concerning marked content generation inside leaders (use-content case). Removed marked content logic from PDFTextUtil and concentrated it in PDFContentGenerator to make Artifact generation more uniform. Not only text generates Artifacts but inside leaders images can also be Artifacts. Some code simplifications. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765525 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/pdf/PDFTextUtil.java | 52 +---------------- .../apache/fop/render/pdf/PDFContentGenerator.java | 46 ++++++++++----- .../apache/fop/render/pdf/PDFDocumentHandler.java | 18 +++--- .../apache/fop/render/pdf/PDFImageHandlerSVG.java | 2 +- src/java/org/apache/fop/render/pdf/PDFPainter.java | 66 +++++++++------------- 5 files changed, 72 insertions(+), 112 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/pdf/PDFTextUtil.java b/src/java/org/apache/fop/pdf/PDFTextUtil.java index bb8816995..6640f9b80 100644 --- a/src/java/org/apache/fop/pdf/PDFTextUtil.java +++ b/src/java/org/apache/fop/pdf/PDFTextUtil.java @@ -48,7 +48,6 @@ public abstract class PDFTextUtil { public static final int TR_CLIP = 7; private boolean inTextObject = false; - private boolean artifactMode = false; private String startText; private String endText; private boolean useMultiByte; @@ -116,15 +115,6 @@ public abstract class PDFTextUtil { return inTextObject; } - /** - * Indicates whether we are in a text object and if that text object represents - * an artifact. - * @return true if in artifact-mode text object - */ - public boolean inArtifactMode() { - return this.artifactMode; - } - /** * Called when a new text object should be started. Be sure to call setFont() before * issuing any text painting commands. @@ -137,52 +127,12 @@ public abstract class PDFTextUtil { this.inTextObject = true; } - /** - * Begin of a regular text object, used for accessibility - * @param mcid of text object - * @param structElemType of parent - */ - public void beginTextObjectAccess(int mcid, String structElemType) { - if (inTextObject) { - throw new IllegalStateException("Already in text object"); - } - write(structElemType + " <>\nBDC\nBT\n"); - this.inTextObject = true; - } - - /** - * Begin of a text object marked as artifact (fo:leader in XSL-FO) text object. - * Used for accessibility. - */ - public void beginArtifactTextObject() { - if (inTextObject) { - throw new IllegalStateException("Already in text object"); - } - write("/Artifact\nBMC\nBT\n"); - this.inTextObject = true; - this.artifactMode = true; - } - /** * Called when a text object should be ended. */ public void endTextObject() { - endTextObject(false); - } - - /** - * Called when a text object should be ended. - * @param accessEnabled indicating if accessibility is turned on or not - */ - public void endTextObject(boolean accessEnabled) { checkInTextObject(); - if (accessEnabled) { - write("ET\nEMC\n"); - } else { - write("ET\n"); - } - this.artifactMode = false; + write("ET\n"); this.inTextObject = false; initValues(); } diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 750f9a3cf..5f9256e9e 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -57,6 +57,7 @@ public class PDFContentGenerator { /** Text generation utility holding the current font status */ protected PDFTextUtil textutil; + private boolean inArtifactMode; /** * Main constructor. Creates a new PDF stream and additional helper classes for text painting @@ -160,17 +161,31 @@ public class PDFContentGenerator { protected void saveGraphicsState(String structElemType, int sequenceNum) { endTextObject(); currentState.save(); - startAccessSequence(structElemType, sequenceNum); + beginMarkedContentSequence(structElemType, sequenceNum); currentStream.add("q\n"); } /** - * Used for accessibility + * Begins a new marked content sequence (BDC or BMC). If the parameter structElemType is null, + * the sequenceNum is ignored and instead of a BDC with the MCID as parameter, an "Artifact" + * and a BMC command is generated. * @param structElemType Structure Element Type * @param sequenceNum Sequence number */ - protected void startAccessSequence(String structElemType, int sequenceNum) { - currentStream.add(structElemType + " <>\nBDC\n"); + protected void beginMarkedContentSequence(String structElemType, int sequenceNum) { + assert !this.inArtifactMode; + if (structElemType != null) { + currentStream.add(structElemType + " <>\n" + + "BDC\n"); + } else { + currentStream.add("/Artifact\nBMC\n"); + this.inArtifactMode = true; + } + } + + private void endMarkedContentSequence() { + currentStream.add("EMC\n"); + this.inArtifactMode = false; } /** @@ -195,7 +210,7 @@ public class PDFContentGenerator { protected void restoreGraphicsStateAccess() { endTextObject(); currentStream.add("Q\n"); - currentStream.add("EMC\n"); + endMarkedContentSequence(); currentState.restore(); } @@ -205,8 +220,10 @@ public class PDFContentGenerator { * @param structElemType of parent of new text element */ protected void separateTextElements(int mcid, String structElemType) { - textutil.endTextObject(true); - textutil.beginTextObjectAccess(mcid, structElemType); + textutil.endTextObject(); + endMarkedContentSequence(); + beginMarkedContentSequence(structElemType, mcid); + textutil.beginTextObject(); } /** @@ -214,9 +231,8 @@ public class PDFContentGenerator { * separates a text element from fo:leader text element */ public void separateTextElementFromLeader() { - if (!textutil.inArtifactMode()) { - textutil.endTextObject(true); - textutil.beginArtifactTextObject(); + if (!inArtifactMode) { + separateTextElements(0, null); } } @@ -234,7 +250,8 @@ public class PDFContentGenerator { */ protected void beginTextObjectAccess(int mcid, String structElemType) { if (!textutil.isInTextObject()) { - textutil.beginTextObjectAccess(mcid, structElemType); + beginMarkedContentSequence(structElemType, mcid); + textutil.beginTextObject(); } } @@ -242,15 +259,14 @@ public class PDFContentGenerator { * Accessibility begin of LeaderTextObject */ public void beginLeaderTextObject() { - if (!textutil.isInTextObject()) { - textutil.beginArtifactTextObject(); - } + beginTextObjectAccess(0, null); } /** Indicates the end of a text object. */ protected void endTextObject() { if (textutil.isInTextObject()) { - textutil.endTextObject(accessEnabled); + endMarkedContentSequence(); + textutil.endTextObject(); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 7df6c9fee..0a975efc3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -520,15 +520,19 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { * @param mcid sequence number within page */ void addChildToStructElemText(String ptr, int mcid) { - PDFDictionary dict = new PDFDictionary(); - dict.put("Type", new PDFName("MCR")); - dict.put("Pg", this.currentPage); - dict.put("MCID", mcid); PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); - tempStructElem.addKid(dict); - if (!tempStructElem.getLevel1()) { - addMeToParent(tempStructElem); + if (tempStructElem != null) { + PDFDictionary dict = new PDFDictionary(); + dict.put("Type", new PDFName("MCR")); + dict.put("Pg", this.currentPage); + dict.put("MCID", mcid); + tempStructElem.addKid(dict); + if (!tempStructElem.getLevel1()) { + addMeToParent(tempStructElem); + } } + //tempStructElem is null, for example inside fo:leaders in which case + //the text shall be marked as artifact } /** diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index c405a2f2a..fde9e0696 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -124,7 +124,7 @@ public class PDFImageHandlerSVG implements ImageHandler { if (context.getUserAgent().isAccessibilityEnabled()) { String structElemType = pdfContext.getStructElemType(); int sequenceNum = pdfContext.getSequenceNum(); - generator.startAccessSequence(structElemType, sequenceNum); + generator.beginMarkedContentSequence(structElemType, sequenceNum); } generator.setColor(Color.black, false); generator.setColor(Color.black, true); diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 3ab32114c..4c9baf0f6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -135,19 +135,9 @@ public class PDFPainter extends AbstractIFPainter { if (xobject != null) { if (accessEnabled && getContext().hasStructurePointer()) { String ptr = getContext().getStructurePointer(); - mcid = this.documentHandler.getMCID(); - mcid++; // fix for Acro Checker - this.documentHandler.incMCID(); // simulating a parent text element - structElemType = this.documentHandler.getStructElemType(ptr); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getParentTrailerObject(ptr)); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getTrailerObject(ptr)); + prepareImageMCID(ptr); placeImageAccess(rect, xobject); - this.documentHandler.addChildToStructElemImage(ptr, mcid); - this.documentHandler.incMCID(); + addImageMCID(ptr); } else { placeImage(rect, xobject); } @@ -155,27 +145,36 @@ public class PDFPainter extends AbstractIFPainter { } if (accessEnabled && getContext().hasStructurePointer()) { String ptr = getContext().getStructurePointer(); - mcid = this.documentHandler.getMCID(); - mcid++; // fix for Acro Checker - this.documentHandler.incMCID(); // simulating a parent text element - structElemType = this.documentHandler.getStructElemType(ptr); + prepareImageMCID(ptr); + drawImageUsingURI(uri, rect); + addImageMCID(ptr); + } else { + drawImageUsingURI(uri, rect); + } + flushPDFDoc(); + } + + private void prepareImageMCID(String ptr) { + mcid = this.documentHandler.getMCID(); + mcid++; // fix for Acro Checker + this.documentHandler.incMCID(); // simulating a parent text element + structElemType = this.documentHandler.getStructElemType(ptr); + if (structElemType != null) { this.documentHandler.addToTempList( this.documentHandler.getCurrentParentTreeKey(), this.documentHandler.getParentTrailerObject(ptr)); this.documentHandler.addToTempList( this.documentHandler.getCurrentParentTreeKey(), this.documentHandler.getTrailerObject(ptr)); - //PDFRenderingContext pdfContext = new PDFRenderingContext( - // getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); - //pdfContext.setMCID(mcid); - //pdfContext.setStructElemType(structElemType); - drawImageUsingURI(uri, rect); + } + } + + private void addImageMCID(String ptr) { + if (this.structElemType != null) { this.documentHandler.addChildToStructElemImage(ptr, mcid); this.documentHandler.incMCID(); - } else { - drawImageUsingURI(uri, rect); } - flushPDFDoc(); + //If structElemType is null, it means "Artifact" mode (ex. leader with use-content). } /** {@inheritDoc} */ @@ -226,19 +225,9 @@ public class PDFPainter extends AbstractIFPainter { public void drawImage(Document doc, Rectangle rect) throws IFException { if (accessEnabled && getContext().hasStructurePointer()) { String ptr = getContext().getStructurePointer(); - mcid = this.documentHandler.getMCID(); - mcid++; // fix for Acro Checker - this.documentHandler.incMCID(); // simulating a parent text element - structElemType = this.documentHandler.getStructElemType(ptr); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getParentTrailerObject(ptr)); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getTrailerObject(ptr)); + prepareImageMCID(ptr); drawImageUsingDocument(doc, rect); - this.documentHandler.addChildToStructElemImage(ptr, mcid); - this.documentHandler.incMCID(); + addImageMCID(ptr); } else { drawImageUsingDocument(doc, rect); } @@ -338,13 +327,13 @@ public class PDFPainter extends AbstractIFPainter { if (accessEnabled) { String ptr = getContext().getStructurePointer(); int mcId; - String structElType = ""; + String structElType = null; if (ptr != null && ptr.length() > 0) { mcId = this.documentHandler.getMCID(); + structElType = this.documentHandler.getStructElemType(ptr); this.documentHandler.addToTempList( this.documentHandler.getCurrentParentTreeKey(), this.documentHandler.getTrailerObject(ptr)); - structElType = this.documentHandler.getStructElemType(ptr); if (generator.getTextUtil().isInTextObject()) { generator.separateTextElements(mcId, structElType); } @@ -354,6 +343,7 @@ public class PDFPainter extends AbstractIFPainter { this.documentHandler.incMCID(); } else { // + // Leader content is marked as "/Artifact" if (generator.getTextUtil().isInTextObject()) { generator.separateTextElementFromLeader(); } -- cgit v1.2.3 From edba3dbe22abe5b21784ec3f0525ccf50f6acd49 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:11:21 +0000 Subject: Bugfix for navigation elements when parsing intermediate content. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765526 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/intermediate/IFSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 2f5524c2c..e00c88b4a 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -366,7 +366,6 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void startPageTrailer() throws IFException { try { handler.startElement(EL_PAGE_TRAILER); - commitNavigation(); } catch (SAXException e) { throw new IFException("SAX error in startPageTrailer()", e); } @@ -375,6 +374,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler /** {@inheritDoc} */ public void endPageTrailer() throws IFException { try { + commitNavigation(); handler.endElement(EL_PAGE_TRAILER); } catch (SAXException e) { throw new IFException("SAX error in endPageTrailer()", e); -- cgit v1.2.3 From 75fde7d0214aa2c35ce1f4695ae631752ae659fd Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:11:51 +0000 Subject: Some cleanup. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765528 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/accessibility/reduceFOTree.xsl | 6 +++--- src/java/org/apache/fop/render/intermediate/IFParser.java | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/reduceFOTree.xsl b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl index eb808286b..84c500639 100644 --- a/src/java/org/apache/fop/accessibility/reduceFOTree.xsl +++ b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl @@ -75,11 +75,11 @@ + + - - - + diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 0648b6628..f1a921377 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -185,7 +185,6 @@ public class IFParser implements IFConstants { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (delegate != null) { - //delegateStack.push(qName); delegateDepth++; delegate.startElement(uri, localName, qName, attributes); } else { @@ -202,8 +201,6 @@ public class IFParser implements IFConstants { } catch (IFException ife) { handleIFException(ife); } - } else if ("extension-attachments".equals(localName)) { - //TODO implement me } else { handled = false; } -- cgit v1.2.3 From 0fc0d56d8b7b2685ee39c433e1b26d926114d6e7 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Thu, 16 Apr 2009 09:35:11 +0000 Subject: Bugfix: Previous simplification requires keeping track of whether we are in a marked content sequence. Removed unused variable accessEnabled in PDFContentGenerator. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765539 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/pdf/PDFContentGenerator.java | 17 +++++++++++------ .../org/apache/fop/render/pdf/PDFDocumentHandler.java | 2 +- src/java/org/apache/fop/render/pdf/PDFRenderer.java | 3 +-- 3 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 5f9256e9e..73e1945f2 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -50,13 +50,13 @@ public class PDFContentGenerator { /** the current stream to add PDF commands to */ private PDFStream currentStream; - private boolean accessEnabled; // used for accessibility /** drawing state */ protected PDFPaintingState currentState = null; /** Text generation utility holding the current font status */ protected PDFTextUtil textutil; + private boolean inMarkedContentSequence; private boolean inArtifactMode; /** @@ -65,10 +65,9 @@ public class PDFContentGenerator { * @param document the PDF document * @param out the output stream the PDF document is generated to * @param resourceContext the resource context - * @param accessibilityEnabled indicating if accessibility is enabled or not */ public PDFContentGenerator(PDFDocument document, OutputStream out, - PDFResourceContext resourceContext, boolean accessibilityEnabled) { + PDFResourceContext resourceContext) { this.document = document; this.outputStream = out; this.resourceContext = resourceContext; @@ -81,7 +80,6 @@ public class PDFContentGenerator { }; this.currentState = new PDFPaintingState(); - this.accessEnabled = accessibilityEnabled; } /** @@ -173,6 +171,7 @@ public class PDFContentGenerator { * @param sequenceNum Sequence number */ protected void beginMarkedContentSequence(String structElemType, int sequenceNum) { + assert !this.inMarkedContentSequence; assert !this.inArtifactMode; if (structElemType != null) { currentStream.add(structElemType + " <>\n" @@ -181,10 +180,12 @@ public class PDFContentGenerator { currentStream.add("/Artifact\nBMC\n"); this.inArtifactMode = true; } + this.inMarkedContentSequence = true; } private void endMarkedContentSequence() { currentStream.add("EMC\n"); + this.inMarkedContentSequence = false; this.inArtifactMode = false; } @@ -210,7 +211,9 @@ public class PDFContentGenerator { protected void restoreGraphicsStateAccess() { endTextObject(); currentStream.add("Q\n"); - endMarkedContentSequence(); + if (this.inMarkedContentSequence) { + endMarkedContentSequence(); + } currentState.restore(); } @@ -265,7 +268,9 @@ public class PDFContentGenerator { /** Indicates the end of a text object. */ protected void endTextObject() { if (textutil.isInTextObject()) { - endMarkedContentSequence(); + if (this.inMarkedContentSequence) { + endMarkedContentSequence(); + } textutil.endTextObject(); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 0a975efc3..fea606f97 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -372,7 +372,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { this.pageReferences.put(new Integer(index), currentPageRef); this.generator = new PDFContentGenerator(this.pdfDoc, this.outputStream, - this.currentPage, this.accessEnabled); + this.currentPage); // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFPainter's AffineTransform basicPageTransform = new AffineTransform(1, 0, 0, -1, 0, size.height / 1000f); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 2c166f679..c40c94fc4 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -461,8 +461,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf double h = bounds.getHeight(); pageHeight = (int) h; - this.generator = new PDFContentGenerator(this.pdfDoc, this.ostream, this.currentPage, - false); + this.generator = new PDFContentGenerator(this.pdfDoc, this.ostream, this.currentPage); this.borderPainter = new PDFBorderPainter(this.generator); // Transform the PDF's default coordinate system (0,0 at lower left) to the PDFRenderer's -- cgit v1.2.3 From 2a16dbaa207c3e36a43dca0dceaaa1bea51eb87d Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 17 Apr 2009 07:54:38 +0000 Subject: Incorporated some more of the feedback to #46705: - String Constant for "accessibility" - Removed unused constructors - Remove unnecessary null-checks. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765889 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/accessibility/AccessibilityUtil.java | 11 ++ .../apache/fop/accessibility/TransformerNode.java | 141 +++------------------ .../TransformerNodeEndProcessing.java | 22 +--- src/java/org/apache/fop/apps/FOUserAgent.java | 7 +- src/java/org/apache/fop/apps/FopFactory.java | 8 +- .../org/apache/fop/cli/CommandLineOptions.java | 3 +- .../fop/render/pdf/PDFConfigurationConstants.java | 3 +- 7 files changed, 43 insertions(+), 152 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/AccessibilityUtil.java b/src/java/org/apache/fop/accessibility/AccessibilityUtil.java index 0dc5840b6..4063d3f9f 100644 --- a/src/java/org/apache/fop/accessibility/AccessibilityUtil.java +++ b/src/java/org/apache/fop/accessibility/AccessibilityUtil.java @@ -36,12 +36,23 @@ import org.apache.fop.apps.FOUserAgent; */ public class AccessibilityUtil { + /** Constant string for the rendering options key to enable accessibility features. */ + public static final String ACCESSIBILITY = "accessibility"; + private static SAXTransformerFactory tfactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); private static Templates addPtrTemplates; private static Templates reduceFOTemplates; + /** + * Decorates the given {@link DefaultHandler} so the structure tree used for accessibility + * features can be branched off the main content stream. + * @param handler the handler to decorate + * @param userAgent the user agent + * @return the decorated handler + * @throws FOPException if an error occurs setting up the decoration + */ public static DefaultHandler decorateDefaultHandler(DefaultHandler handler, FOUserAgent userAgent) throws FOPException { DefaultHandler transformNode = new TransformerNodeEndProcessing( diff --git a/src/java/org/apache/fop/accessibility/TransformerNode.java b/src/java/org/apache/fop/accessibility/TransformerNode.java index 115c13703..b127a74b5 100644 --- a/src/java/org/apache/fop/accessibility/TransformerNode.java +++ b/src/java/org/apache/fop/accessibility/TransformerNode.java @@ -19,17 +19,12 @@ package org.apache.fop.accessibility; -import java.io.File; - import javax.xml.transform.Result; -import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; -import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; -import javax.xml.transform.stream.StreamSource; import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -46,70 +41,6 @@ class TransformerNode extends DefaultHandler { private TransformerHandler transformerHandler; - /** - * happens after setParams have been broadcast. - * - * @param downstreamHandler - * the handler passed in - * @param xsltFile - * for transform - * @throws FOPException - * for general errors - */ - public TransformerNode(DefaultHandler downstreamHandler, File xsltFile) throws FOPException { - try { - TransformerFactory transFact = TransformerFactory.newInstance(); - SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); - StreamSource ss = new StreamSource(xsltFile); - transformerHandler = saxTFactory.newTransformerHandler(ss); - SAXResult saxResult = new SAXResult(); - saxResult.setHandler(downstreamHandler); - transformerHandler.setResult(saxResult); - } catch (TransformerConfigurationException t) { - throw new FOPException(t); - } - } - - /** - * - * @param result - * of transform - * @param xsltFile - * for transform - * @throws FOPException - * for general errors - */ - public TransformerNode(Result result, File xsltFile) throws FOPException { - try { - TransformerFactory transFact = TransformerFactory.newInstance(); - SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); - StreamSource ss = new StreamSource(xsltFile); - transformerHandler = saxTFactory.newTransformerHandler(ss); - transformerHandler.setResult(result); - } catch (TransformerConfigurationException t) { - throw new FOPException(t); - } - } - - /** - * This is part of a two phase construction. Call this, then call - * initResult. - * - * @param xsltFile - * for transform - * @throws FOPException - * for general errors - */ - public TransformerNode(Source xsltFile) throws FOPException { - try { - TransformerFactory transFact = TransformerFactory.newInstance(); - SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); - transformerHandler = saxTFactory.newTransformerHandler(xsltFile); - } catch (TransformerConfigurationException t) { - throw new FOPException(t); - } - } - /** * This is part of a two phase construction. Call this, then call * initResult. @@ -142,81 +73,59 @@ class TransformerNode extends DefaultHandler { /******************** start of ContentHandler ***************************/ /** {@inheritDoc} */ public void setDocumentLocator(Locator locator) { - if (transformerHandler != null) { - transformerHandler.setDocumentLocator(locator); - } + transformerHandler.setDocumentLocator(locator); } /** {@inheritDoc} */ public void startDocument() throws SAXException { - if (transformerHandler != null) { - transformerHandler.startDocument(); - } + transformerHandler.startDocument(); } /** {@inheritDoc} */ public void endDocument() throws SAXException { - if (transformerHandler != null) { - transformerHandler.endDocument(); - } + transformerHandler.endDocument(); } /** {@inheritDoc} */ public void processingInstruction(String target, String data) throws SAXException { - if (transformerHandler != null) { - transformerHandler.processingInstruction(target, data); - } + transformerHandler.processingInstruction(target, data); } /** {@inheritDoc} */ public void startElement(String uri, String local, String raw, Attributes attrs) throws SAXException { AttributesImpl ai = new AttributesImpl(attrs); - if (transformerHandler != null) { - transformerHandler.startElement(uri, local, raw, ai); - } + transformerHandler.startElement(uri, local, raw, ai); } /** {@inheritDoc} */ public void characters(char[] ch, int start, int length) throws SAXException { - if (transformerHandler != null) { - transformerHandler.characters(ch, start, length); - } + transformerHandler.characters(ch, start, length); } /** {@inheritDoc} */ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { - if (transformerHandler != null) { - transformerHandler.ignorableWhitespace(ch, start, length); - } + transformerHandler.ignorableWhitespace(ch, start, length); } /** {@inheritDoc} */ public void endElement(String uri, String local, String raw) throws SAXException { - if (transformerHandler != null) { - transformerHandler.endElement(uri, local, raw); - } + transformerHandler.endElement(uri, local, raw); } /** {@inheritDoc} */ public void skippedEntity(String string) throws SAXException { - if (transformerHandler != null) { - transformerHandler.skippedEntity(string); - } + transformerHandler.skippedEntity(string); } /** {@inheritDoc} */ public void startPrefixMapping(String string, String string1) throws SAXException { - if (transformerHandler != null) { - transformerHandler.startPrefixMapping(string, string1); - } + transformerHandler.startPrefixMapping(string, string1); } /** {@inheritDoc} */ public void endPrefixMapping(String string) throws SAXException { - if (transformerHandler != null) { - transformerHandler.endPrefixMapping(string); - } + transformerHandler.endPrefixMapping(string); } /***************************** LexicalHandlerImpl **************************/ @@ -231,9 +140,7 @@ class TransformerNode extends DefaultHandler { * - if parser fails */ public void startDTD(String name, String pid, String lid) throws SAXException { - if (transformerHandler != null) { - transformerHandler.startDTD(name, pid, lid); - } + transformerHandler.startDTD(name, pid, lid); } /** @@ -243,9 +150,7 @@ class TransformerNode extends DefaultHandler { * - if parser fails */ public void endDTD() throws SAXException { - if (transformerHandler != null) { - transformerHandler.endDTD(); - } + transformerHandler.endDTD(); } /** @@ -257,9 +162,7 @@ class TransformerNode extends DefaultHandler { * - if parser fails */ public void startEntity(String string) throws SAXException { - if (transformerHandler != null) { - transformerHandler.startEntity(string); - } + transformerHandler.startEntity(string); } /** @@ -271,9 +174,7 @@ class TransformerNode extends DefaultHandler { * - if paser fails */ public void endEntity(String string) throws SAXException { - if (transformerHandler != null) { - transformerHandler.endEntity(string); - } + transformerHandler.endEntity(string); } /** @@ -283,9 +184,7 @@ class TransformerNode extends DefaultHandler { * - parser fails */ public void startCDATA() throws SAXException { - if (transformerHandler != null) { - transformerHandler.startCDATA(); - } + transformerHandler.startCDATA(); } /** @@ -295,9 +194,7 @@ class TransformerNode extends DefaultHandler { * - if paser fails */ public void endCDATA() throws SAXException { - if (transformerHandler != null) { - transformerHandler.endCDATA(); - } + transformerHandler.endCDATA(); } /** @@ -312,9 +209,7 @@ class TransformerNode extends DefaultHandler { * - if paser fails */ public void comment(char[] charArray, int int1, int int2) throws SAXException { - if (transformerHandler != null) { - transformerHandler.comment(charArray, int1, int2); - } + transformerHandler.comment(charArray, int1, int2); } /******************** End of Lexical Handler ***********************/ diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java index 8e02c67cd..34974233a 100644 --- a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java +++ b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java @@ -20,7 +20,6 @@ package org.apache.fop.accessibility; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.InputStream; import javax.xml.parsers.SAXParser; @@ -35,6 +34,8 @@ import javax.xml.transform.stream.StreamSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import org.apache.commons.io.output.ByteArrayOutputStream; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; @@ -66,25 +67,6 @@ class TransformerNodeEndProcessing extends TransformerNode { super.initResult(res1); } - /** - * Do a transform, but perform special processing at the end for the access - * stuff. - * - * @param xsltFile Transform to do. - * @param fopHandler Used in the end processing - * @param userAgent the userAgent - * @throws FOPException if transform fails - */ - - public TransformerNodeEndProcessing(Source xsltFile, DefaultHandler fopHandler, - FOUserAgent userAgent) throws FOPException { - super(xsltFile); - delegateHandler = fopHandler; - this.userAgent = userAgent; - Result res1 = new StreamResult(enrichedFOBuffer); - super.initResult(res1); - } - /** {@inheritDoc} */ public void endDocument() throws SAXException { super.endDocument(); diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 64ab413dc..13db8d5ef 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -37,6 +37,7 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.fop.Version; +import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.events.DefaultEventBroadcaster; import org.apache.fop.events.Event; import org.apache.fop.events.EventBroadcaster; @@ -155,8 +156,8 @@ public class FOUserAgent { this.factory = factory; setBaseURL(factory.getBaseURL()); setTargetResolution(factory.getTargetResolution()); - if (this.getRendererOptions().get("accessibility") == null) { - this.rendererOptions.put("accessibility", Boolean.FALSE); + if (this.getRendererOptions().get(AccessibilityUtil.ACCESSIBILITY) == null) { + this.rendererOptions.put(AccessibilityUtil.ACCESSIBILITY, Boolean.FALSE); } } @@ -654,7 +655,7 @@ public class FOUserAgent { * @return true if accessibility is enabled */ public boolean isAccessibilityEnabled() { - Boolean enabled = (Boolean)this.getRendererOptions().get("accessibility"); + Boolean enabled = (Boolean)this.getRendererOptions().get(AccessibilityUtil.ACCESSIBILITY); if (enabled != null) { return enabled.booleanValue(); } else { diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 1a5c3cfd4..6693f33c4 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -41,6 +41,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.image.loader.ImageContext; import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.ElementMappingRegistry; import org.apache.fop.fonts.FontCache; @@ -99,7 +100,7 @@ public class FopFactory implements ImageContext { * external-graphics. */ private String base = null; - + /** * Controls if accessibility is turned on or off */ @@ -186,7 +187,8 @@ public class FopFactory implements ImageContext { */ public FOUserAgent newFOUserAgent() { FOUserAgent userAgent = new FOUserAgent(this); - userAgent.getRendererOptions().put("accessibility", Boolean.valueOf(this.accessibility)); + userAgent.getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, + Boolean.valueOf(this.accessibility)); return userAgent; } @@ -197,7 +199,7 @@ public class FopFactory implements ImageContext { void setAccessibility(boolean value) { this.accessibility = value; } - + /** * Returns a new {@link Fop} instance. FOP will be configured with a default user agent * instance. diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index cb6756476..e82ce13a7 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -36,6 +36,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.Version; +import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; @@ -333,7 +334,7 @@ public class CommandLineOptions { } else if (args[i].equals("-if")) { i = i + parseIntermediateFormatOption(args, i); } else if (args[i].equals("-a")) { - this.renderingOptions.put("accessibility", Boolean.TRUE); + this.renderingOptions.put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); } else if (args[i].equals("-v")) { printVersion(); return false; diff --git a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java index 2f4379795..d5e6b0b63 100644 --- a/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java +++ b/src/java/org/apache/fop/render/pdf/PDFConfigurationConstants.java @@ -19,6 +19,7 @@ package org.apache.fop.render.pdf; + /** * Constants used for configuring PDF output. */ @@ -49,6 +50,4 @@ public interface PDFConfigurationConstants { * PDF/X profile is active). */ String KEY_DISABLE_SRGB_COLORSPACE = "disable-srgb-colorspace"; - /** PDF Accessibility */ - String ACCESSIBLITY = "accessibility"; } -- cgit v1.2.3 From 7882e4711f9bb1b32e3c4f17eaad41a3e4864957 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 17 Apr 2009 07:56:17 +0000 Subject: Removed FO to role mapping from the PDF library and moved it next to the renderer. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765890 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/pdf/PDFStructElem.java | 105 +++++----------- .../org/apache/fop/render/pdf/FOToPDFRoleMap.java | 133 +++++++++++++++++++++ .../apache/fop/render/pdf/PDFDocumentHandler.java | 14 ++- 3 files changed, 170 insertions(+), 82 deletions(-) create mode 100644 src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index 408b1f2c7..e36f5fd42 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -25,81 +25,21 @@ package org.apache.fop.pdf; public class PDFStructElem extends PDFDictionary { private PDFObject parentObject = null; - private String source = ""; private boolean level1 = false; /** * Create the /StructTreeRoot dictionary - * @param fo passed in fo object * @param parent Parent of this PDFStructElem + * @param structureType the structure type for the element */ - public PDFStructElem(String fo, PDFObject parent) { + public PDFStructElem(PDFObject parent, PDFName structureType) { super(); if (parent instanceof PDFStructElem) { parentObject = (PDFStructElem) parent; } put("Type", new PDFName("StructElem")); - source = fo; - //TODO Move this into the render/pdf package. The PDF library shall not contain FO knowledge - if ("block".equals(fo)) { - put("S", new PDFName("P")); - } else if ("inline".equals(fo) || "wrapper".equals(fo) || "character".equals(fo)) { - put("S", new PDFName("Span")); - } else if ("table-cell".equals(fo)) { - PDFStructElem grandParent = (PDFStructElem) - ((PDFStructElem)parent).getParentStructElem(); - String s = grandParent.getSource(); - if ("table-header".equals(s)) { - put("S", new PDFName("TH")); - } else { - put("S", new PDFName("TD")); - } - } else if ("table-row".equals(fo)) { - put("S", new PDFName("TR")); - } else if ("root".equals(fo)) { - put("S", new PDFName("Document")); - } else if ("page-sequence".equals(fo)) { - put("S", new PDFName("Part")); - } else if ("flow".equals(fo) || "static-content".equals(fo)) { - put("S", new PDFName("Sect")); - } else if ("page-number".equals(fo) || "page-number-citation".equals(fo) - || "page-number-citation-last".equals(fo)) { - put("S", new PDFName("Quote")); - } else if ("external-graphic".equals(fo) || "instream-foreign-object".equals(fo)) { - put("S", new PDFName("Figure")); - } else if ("table".equals(fo)) { - put("S", new PDFName("Table")); - } else if ("table-body".equals(fo)) { - put("S", new PDFName("TBody")); - } else if ("table-header".equals(fo)) { - put("S", new PDFName("THead")); - } else if ("table-footer".equals(fo)) { - put("S", new PDFName("TFoot")); - } else if ("list-block".equals(fo)) { - put("S", new PDFName("L")); - } else if ("list-item".equals(fo)) { - put("S", new PDFName("LI")); - } else if ("list-item-label".equals(fo)) { - put("S", new PDFName("Lbl")); - } else if ("list-item-body".equals(fo)) { - put("S", new PDFName("LBody")); - } else if ("block-container".equals(fo)) { - put("S", new PDFName("Div")); - } else if ("basic-link".equals(fo)) { - put("S", new PDFName("Link")); - } else if ("footnote".equals(fo)) { - put("S", new PDFName("Note")); - } else if ("footnote-body".equals(fo)) { - put("S", new PDFName("Sect")); - } else if ("marker".equals(fo)) { - put("S", new PDFName("Private")); - } else { - log.error("Accessibility: PDFStructElem constructor is missing: " + fo); - } + setStructureType(structureType); setParent(parent); - if (!"external-graphic".equals(fo) && !"instream-foreign-object".equals(fo)) { - put("K", new PDFArray()); - } } /** @@ -137,14 +77,6 @@ public class PDFStructElem extends PDFDictionary { } } - /** - * Get the source of this StructElem - * @return the source - */ - public String getSource() { - return source; - } - /** * The kids of this StructElem * @return the kids @@ -158,18 +90,23 @@ public class PDFStructElem extends PDFDictionary { * @param kid to be added */ public void addKid(PDFObject kid) { - getKids().add(kid); + PDFArray kids = getKids(); + if (kids == null) { + kids = new PDFArray(); + put("K", kids); + } + kids.add(kid); } /** - * Add a kid, but only if it does not already exist + * Add a kid, but only if it does not already exist. * @param kid to be added * @return true if kid did not already exist */ public boolean addUniqueKid(PDFObject kid) { PDFArray mArray = getKids(); - if (!mArray.contains(kid)) { - getKids().add(kid); + if (mArray == null || !mArray.contains(kid)) { + addKid(kid); return true; } else { return false; @@ -177,8 +114,7 @@ public class PDFStructElem extends PDFDictionary { } /** - * Add kid referenced through mcid integer - * used fo:external-graphic + * Add kid referenced through mcid integer. Used for images. * @param mcid of this kid */ public void addMCIDKid(int mcid) { @@ -193,4 +129,19 @@ public class PDFStructElem extends PDFDictionary { put("Pg", (PDFObject) pageObject); } + /** + * Sets the structure type (the "S" entry). + * @param type the structure type + */ + public void setStructureType(PDFName type) { + put("S", type); + } + + /** + * Returns the structure type of this structure element. + * @return the structure type + */ + public PDFName getStructureType() { + return (PDFName)get("S"); + } } diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java new file mode 100644 index 000000000..f1de1a65b --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java @@ -0,0 +1,133 @@ +/* + * 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.Map; + +import org.apache.fop.pdf.PDFName; +import org.apache.fop.pdf.PDFObject; +import org.apache.fop.pdf.PDFStructElem; + +/** + * This class provides the standard mappings from Formatting Objects to PDF structure types. + */ +public class FOToPDFRoleMap { + + private static final Map STANDARD_MAPPINGS = new java.util.HashMap(); + + private static final PDFName TFOOT = new PDFName("TFoot"); + private static final PDFName THEAD = new PDFName("THead"); + + static { + addSimpleMapping("block", new PDFName("P")); + addSimpleMapping("block-container", new PDFName("Div")); + + PDFName st = new PDFName("Span"); + addSimpleMapping("inline", st); + addSimpleMapping("wrapper", st); + addSimpleMapping("character", st); + + addSimpleMapping("root", new PDFName("Document")); + addSimpleMapping("page-sequence", new PDFName("Part")); + addSimpleMapping("flow", new PDFName("Sect")); + addSimpleMapping("static-content", new PDFName("Sect")); + + st = new PDFName("Quote"); + addSimpleMapping("page-number", st); + addSimpleMapping("page-number-citation", st); + addSimpleMapping("page-number-citation-last", st); + + st = new PDFName("Figure"); + addSimpleMapping("external-graphic", st); + addSimpleMapping("instream-foreign-object", st); + + addSimpleMapping("table", new PDFName("Table")); + addSimpleMapping("table-body", new PDFName("TBody")); + addSimpleMapping("table-header", THEAD); + addSimpleMapping("table-footer", TFOOT); + addSimpleMapping("table-row", new PDFName("TR")); + STANDARD_MAPPINGS.put("table-cell", new TableCellMapper()); + + addSimpleMapping("list-block", new PDFName("L")); + addSimpleMapping("list-item", new PDFName("LI")); + addSimpleMapping("list-item-label", new PDFName("Lbl")); + addSimpleMapping("list-item-body", new PDFName("LBody")); + + addSimpleMapping("basic-link", new PDFName("Link")); + addSimpleMapping("footnote", new PDFName("Note")); + addSimpleMapping("footnote-body", new PDFName("Sect")); + addSimpleMapping("marker", new PDFName("Private")); + } + + private static void addSimpleMapping(String fo, PDFName structureType) { + STANDARD_MAPPINGS.put(fo, new SimpleMapper(structureType)); + } + + /** + * Maps a Formatting Object to a PDFName representing the associated structure type. + * @param fo the formatting object's local name + * @param parent the parent of the structure element to be mapped + * @return the structure type or null if no match could be found + */ + public static PDFName mapFormattingObject(String fo, PDFObject parent) { + Mapper mapper = (Mapper)STANDARD_MAPPINGS.get(fo); + if (mapper != null) { + return mapper.getStructureType(parent); + } + return null; + } + + private interface Mapper { + PDFName getStructureType(PDFObject parent); + } + + private static class SimpleMapper implements Mapper { + + private PDFName structureType; + + public SimpleMapper(PDFName structureType) { + this.structureType = structureType; + } + + public PDFName getStructureType(PDFObject parent) { + return structureType; + } + + } + + private static class TableCellMapper implements Mapper { + + private static final PDFName TD = new PDFName("TD"); + private static final PDFName TH = new PDFName("TH"); + + public PDFName getStructureType(PDFObject parent) { + PDFStructElem grandParent = (PDFStructElem) + ((PDFStructElem)parent).getParentStructElem(); + //TODO What to do with cells from table-footer? Currently they are mapped on TD. + if (THEAD.equals(grandParent.getStructureType())) { + return TH; + } else { + return TD; + } + } + + } + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index fea606f97..7f5a9be5f 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -220,7 +220,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { log.info("Accessibility is enabled"); PDFStructTreeRoot structTreeRoot = this.pdfDoc.getFactory().makeStructTreeRoot(); this.pdfDoc.getRoot().setStructTreeRoot(structTreeRoot); - PDFStructElem structElemDocument = new PDFStructElem("root", structTreeRoot); + PDFStructElem structElemDocument = new PDFStructElem(structTreeRoot, + FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot)); this.pdfDoc.assignObjectNumber(structElemDocument); this.pdfDoc.addTrailerObject(structElemDocument); structTreeRoot.addKid(structElemDocument); @@ -306,7 +307,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); } PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); - PDFStructElem structElemPart = new PDFStructElem("page-sequence", parent); + PDFStructElem structElemPart = new PDFStructElem(parent, + FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); this.pdfDoc.assignObjectNumber(structElemPart); this.pdfDoc.addTrailerObject(structElemPart); parent.addKid(structElemPart); @@ -325,8 +327,9 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { Node node = nodes.item(i); if (node.getNodeName().equals("fo:flow") || node.getNodeName().equals("fo:static-content")) { - PDFStructElem structElemSect = new PDFStructElem( - node.getLocalName(), structElemPart); + PDFStructElem structElemSect = new PDFStructElem(structElemPart, + FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), + structElemPart)); this.pdfDoc.assignObjectNumber(structElemSect); this.pdfDoc.addTrailerObject(structElemSect); structElemPart.addKid(structElemSect); @@ -590,7 +593,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { ptr = ""; } String s = me.getLocalName(); - PDFStructElem structElem = new PDFStructElem(s, parent); + PDFStructElem structElem = new PDFStructElem(parent, + FOToPDFRoleMap.mapFormattingObject(s, parent)); this.pdfDoc.assignObjectNumber(structElem); this.pdfDoc.addTrailerObject(structElem); if (depth == 1) { -- cgit v1.2.3 From eeb0cc4fb8f3816e7507ce22de0fb4b9dd433f1c Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 17 Apr 2009 10:10:15 +0000 Subject: Made use of method overloading to homogenize the addition of standard mappings. A bit of pretty-printing. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765928 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/pdf/FOToPDFRoleMap.java | 74 ++++++++++++---------- 1 file changed, 41 insertions(+), 33 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java index f1de1a65b..f0cc39698 100644 --- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java +++ b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java @@ -36,48 +36,56 @@ public class FOToPDFRoleMap { private static final PDFName THEAD = new PDFName("THead"); static { - addSimpleMapping("block", new PDFName("P")); - addSimpleMapping("block-container", new PDFName("Div")); + addMapping("block", "P"); + addMapping("block-container", "Div"); PDFName st = new PDFName("Span"); - addSimpleMapping("inline", st); - addSimpleMapping("wrapper", st); - addSimpleMapping("character", st); + addMapping("inline", st); + addMapping("wrapper", st); + addMapping("character", st); - addSimpleMapping("root", new PDFName("Document")); - addSimpleMapping("page-sequence", new PDFName("Part")); - addSimpleMapping("flow", new PDFName("Sect")); - addSimpleMapping("static-content", new PDFName("Sect")); + addMapping("root", "Document"); + addMapping("page-sequence", "Part"); + addMapping("flow", "Sect"); + addMapping("static-content", "Sect"); st = new PDFName("Quote"); - addSimpleMapping("page-number", st); - addSimpleMapping("page-number-citation", st); - addSimpleMapping("page-number-citation-last", st); + addMapping("page-number", st); + addMapping("page-number-citation", st); + addMapping("page-number-citation-last", st); st = new PDFName("Figure"); - addSimpleMapping("external-graphic", st); - addSimpleMapping("instream-foreign-object", st); - - addSimpleMapping("table", new PDFName("Table")); - addSimpleMapping("table-body", new PDFName("TBody")); - addSimpleMapping("table-header", THEAD); - addSimpleMapping("table-footer", TFOOT); - addSimpleMapping("table-row", new PDFName("TR")); - STANDARD_MAPPINGS.put("table-cell", new TableCellMapper()); - - addSimpleMapping("list-block", new PDFName("L")); - addSimpleMapping("list-item", new PDFName("LI")); - addSimpleMapping("list-item-label", new PDFName("Lbl")); - addSimpleMapping("list-item-body", new PDFName("LBody")); - - addSimpleMapping("basic-link", new PDFName("Link")); - addSimpleMapping("footnote", new PDFName("Note")); - addSimpleMapping("footnote-body", new PDFName("Sect")); - addSimpleMapping("marker", new PDFName("Private")); + addMapping("external-graphic", st); + addMapping("instream-foreign-object", st); + + addMapping("table", "Table"); + addMapping("table-body", "TBody"); + addMapping("table-header", THEAD); + addMapping("table-footer", TFOOT); + addMapping("table-row", "TR"); + addMapping("table-cell", new TableCellMapper()); + + addMapping("list-block", "L"); + addMapping("list-item", "LI"); + addMapping("list-item-label", "Lbl"); + addMapping("list-item-body", "LBody"); + + addMapping("basic-link", "Link"); + addMapping("footnote", "Note"); + addMapping("footnote-body", "Sect"); + addMapping("marker", "Private"); } - private static void addSimpleMapping(String fo, PDFName structureType) { - STANDARD_MAPPINGS.put(fo, new SimpleMapper(structureType)); + private static void addMapping(String fo, String pdfName) { + addMapping(fo, new PDFName(pdfName)); + } + + private static void addMapping(String fo, PDFName pdfName) { + addMapping(fo, new SimpleMapper(pdfName)); + } + + private static void addMapping(String fo, Mapper mapper) { + STANDARD_MAPPINGS.put(fo, mapper); } /** -- cgit v1.2.3 From 8eefdf7d68cc640ca4c3d4ac331e5af1a9049ee0 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 17 Apr 2009 12:10:07 +0000 Subject: Added support for adding natural language information on page-sequence and document level to a tagged PDF. The document-level language is assumed to be the language of the first page-sequence. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765965 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/area/AreaTreeParser.java | 3 +- src/java/org/apache/fop/pdf/PDFStructElem.java | 29 ++++++++++++++ .../apache/fop/render/intermediate/IFContext.java | 19 +++++++++ .../apache/fop/render/intermediate/IFParser.java | 22 ++++++++--- .../apache/fop/render/intermediate/IFRenderer.java | 14 +++++++ .../fop/render/intermediate/IFSerializer.java | 25 ++++++++++++ .../apache/fop/render/pdf/PDFDocumentHandler.java | 31 ++++++++++----- src/java/org/apache/fop/util/XMLUtil.java | 36 +++++++++++++++++ test/java/org/apache/fop/util/XMLUtilTestCase.java | 45 ++++++++++++++++++++++ .../standard-testcases/page-sequence_language.xml | 6 +++ 10 files changed, 214 insertions(+), 16 deletions(-) create mode 100644 test/java/org/apache/fop/util/XMLUtilTestCase.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index bb7e47dd3..d2af24a01 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -85,6 +85,7 @@ import org.apache.fop.util.ContentHandlerFactory; import org.apache.fop.util.ContentHandlerFactoryRegistry; import org.apache.fop.util.ConversionUtils; import org.apache.fop.util.DefaultErrorListener; +import org.apache.fop.util.XMLConstants; import org.apache.fop.util.XMLUtil; /** @@ -1134,7 +1135,7 @@ public class AreaTreeParser { for (int i = 0, c = atts.getLength(); i < c; i++) { String ns = atts.getURI(i); if (ns.length() > 0) { - if ("http://www.w3.org/2000/xmlns/".equals(ns)) { + if (XMLConstants.XMLNS_NAMESPACE_URI.equals(ns)) { continue; } QName qname = new QName(ns, atts.getQName(i)); diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index e36f5fd42..2f8898a19 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -19,6 +19,10 @@ package org.apache.fop.pdf; +import java.util.Locale; + +import org.apache.fop.util.XMLUtil; + /** * Class representing a PDF Structure Element. */ @@ -144,4 +148,29 @@ public class PDFStructElem extends PDFDictionary { public PDFName getStructureType() { return (PDFName)get("S"); } + + /** + * Sets the language of this structure element. + * @param language the language (as defined in the section about + * "Natural Language Specification") + */ + public void setLanguage(String language) { + put("Lang", language); + } + + /** + * Sets the language of this structure element. + * @param language the language + */ + public void setLanguage(Locale language) { + setLanguage(XMLUtil.toRFC3066(language)); + } + + /** + * Returns the language of this structure element. + * @return the language (or null if no language was specified) + */ + public String getLanguage() { + return (String)get("Lang"); + } } diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index b534cfa56..f052846d3 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -20,6 +20,7 @@ package org.apache.fop.render.intermediate; import java.util.Collections; +import java.util.Locale; import java.util.Map; import org.apache.xmlgraphics.util.QName; @@ -43,6 +44,8 @@ public class IFContext { /** foreign attributes: Map */ private Map foreignAttributes = Collections.EMPTY_MAP; + private Locale language; + private String structurePointer; /** @@ -110,6 +113,22 @@ public class IFContext { setForeignAttributes(null); } + /** + * Sets the currently applicable language. + * @param lang the language + */ + public void setLanguage(Locale lang) { + this.language = lang; + } + + /** + * Returns the currently applicable language. + * @return the language (or null if the language is undefined) + */ + public Locale getLanguage() { + return this.language; + } + /** * Sets the structure pointer for the following painted marks. This method is used when * accessibility features are enabled. diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index f1a921377..e374f82fa 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -25,6 +25,7 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.util.Map; +import java.util.Set; import javax.xml.transform.Source; import javax.xml.transform.Transformer; @@ -73,6 +74,15 @@ public class IFParser implements IFConstants { private static SAXTransformerFactory tFactory = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + private static Set handledNamespaces = new java.util.HashSet(); + + static { + handledNamespaces.add(XMLNS_NAMESPACE_URI); + handledNamespaces.add(XML_NAMESPACE); + handledNamespaces.add(NAMESPACE); + handledNamespaces.add(XLINK_NAMESPACE); + } + /** * Parses an intermediate file and paints it. * @param src the Source instance pointing to the intermediate file @@ -357,6 +367,11 @@ public class IFParser implements IFConstants { 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)); + } Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); documentHandler.startPageSequence(id); @@ -365,6 +380,7 @@ public class IFParser implements IFConstants { public void endElement() throws IFException { documentHandler.endPageSequence(); + documentHandler.getContext().setLanguage(null); } } @@ -643,11 +659,7 @@ public class IFParser implements IFConstants { for (int i = 0, c = atts.getLength(); i < c; i++) { String ns = atts.getURI(i); if (ns.length() > 0) { - if ("http://www.w3.org/2000/xmlns/".equals(ns)) { - continue; - } else if (NAMESPACE.equals(ns)) { - continue; - } else if (XLINK_NAMESPACE.equals(ns)) { + if (handledNamespaces.contains(ns)) { continue; } if (foreignAttributes == null) { diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 905277f1b..7c0bf8abc 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -30,6 +30,7 @@ import java.io.OutputStream; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Stack; @@ -493,6 +494,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { try { if (this.inPageSequence) { documentHandler.endPageSequence(); + documentHandler.getContext().setLanguage(null); } else { if (this.documentMetadata == null) { this.documentMetadata = createDefaultDocumentMetadata(); @@ -502,6 +504,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { this.inPageSequence = true; } establishForeignAttributes(pageSequence.getForeignAttributes()); + documentHandler.getContext().setLanguage(toLocale(pageSequence)); documentHandler.startPageSequence(null); resetForeignAttributes(); processExtensionAttachments(pageSequence); @@ -510,6 +513,17 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } } + private Locale toLocale(PageSequence pageSequence) { + if (pageSequence.getLanguage() != null) { + if (pageSequence.getCountry() != null) { + return new Locale(pageSequence.getLanguage(), pageSequence.getCountry()); + } else { + return new Locale(pageSequence.getLanguage()); + } + } + return null; + } + private Metadata createDefaultDocumentMetadata() { Metadata xmp = new Metadata(); DublinCoreAdapter dc = DublinCoreSchema.getAdapter(xmp); diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index e00c88b4a..2d009d58d 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -29,7 +29,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Stack; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; @@ -267,6 +269,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); } + applyLanguage(atts); addForeignAttributes(atts); handler.startElement(EL_PAGE_SEQUENCE, atts); if (this.getUserAgent().isAccessibilityEnabled()) { @@ -301,6 +304,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void endPageSequence() throws IFException { try { handler.endElement(EL_PAGE_SEQUENCE); + popLanguage(); } catch (SAXException e) { throw new IFException("SAX error in endPageSequence()", e); } @@ -831,4 +835,25 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } } + private Stack languageStack = new Stack(); + + private void applyLanguage(AttributesImpl atts) { + Locale lang = getContext().getLanguage(); + if (lang != null) { + if (languageStack.isEmpty() || !languageStack.peek().equals(lang)) { + atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA, + XMLUtil.toRFC3066(lang)); + } + languageStack.push(lang); + } else { + assert languageStack.isEmpty(); + } + } + + private void popLanguage() { + if (!languageStack.isEmpty()) { + languageStack.pop(); + } + } + } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 7f5a9be5f..aba4cceb3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -70,6 +70,7 @@ 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.util.XMLUtil; /** * {@code IFDocumentHandler} implementation that produces PDF. @@ -82,7 +83,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** the following variables are used for accessibility */ private int pageSequenceCounter; private DocumentBuilder parser = null; - private Document doc = null; + private Document reducedFOTree = null; private Map structElemType = new HashMap(); private boolean accessEnabled = false; private int parentTreeKey = -1; @@ -226,10 +227,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { this.pdfDoc.addTrailerObject(structElemDocument); structTreeRoot.addKid(structElemDocument); - //TODO: make document language variable, see note on wiki page PDF Accessibility - //TODO: and follow-up emails on fop-dev - this.pdfDoc.getRoot().setLanguage("en"); - parentTree = new PDFParentTree(); pageSequenceCounter = 0; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -271,7 +268,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { getStructTreeRoot().addParentTree(parentTree); pdfDoc.outputTrailer(this.outputStream); parser = null; - doc = null; + reducedFOTree = null; structElemType = null; parentTree = null; structTreeMap = null; @@ -298,17 +295,31 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public void startPageSequence(String id) throws IFException { - //TODO page sequence title, country and language + //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 (getUserAgent().isAccessibilityEnabled()) { try { - if (doc == null) { - doc = parser.parse( + if (this.pdfDoc.getRoot().getLanguage() == null) { + //No language has been set on the first page-sequence, so fall back to "en". + this.pdfDoc.getRoot().setLanguage("en"); + } + + if (reducedFOTree == null) { + reducedFOTree = parser.parse( new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); } PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); PDFStructElem structElemPart = new PDFStructElem(parent, FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); + if (getContext().getLanguage() != null) { + structElemPart.setLanguage(getContext().getLanguage()); + } this.pdfDoc.assignObjectNumber(structElemPart); this.pdfDoc.addTrailerObject(structElemPart); parent.addKid(structElemPart); @@ -320,7 +331,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { "http://www.w3.org/1999/XSL/Format"); xpath.setNamespaceContext(namespaceContext); - NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, doc, + NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET); for (int i = 0, n = nodes.getLength(); i < n; i++) { diff --git a/src/java/org/apache/fop/util/XMLUtil.java b/src/java/org/apache/fop/util/XMLUtil.java index e42bef90e..644b7c22d 100644 --- a/src/java/org/apache/fop/util/XMLUtil.java +++ b/src/java/org/apache/fop/util/XMLUtil.java @@ -21,6 +21,7 @@ package org.apache.fop.util; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; +import java.util.Locale; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -170,4 +171,39 @@ public class XMLUtil implements XMLConstants { 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]); + } + } + } diff --git a/test/java/org/apache/fop/util/XMLUtilTestCase.java b/test/java/org/apache/fop/util/XMLUtilTestCase.java new file mode 100644 index 000000000..3e86b978e --- /dev/null +++ b/test/java/org/apache/fop/util/XMLUtilTestCase.java @@ -0,0 +1,45 @@ +/* + * 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; + +import junit.framework.TestCase; + +/** + * Tests {@link XMLUtil}. + */ +public class XMLUtilTestCase extends TestCase { + + 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"))); + } + + 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")); + } +} diff --git a/test/layoutengine/standard-testcases/page-sequence_language.xml b/test/layoutengine/standard-testcases/page-sequence_language.xml index 93238e282..f2fa610bc 100644 --- a/test/layoutengine/standard-testcases/page-sequence_language.xml +++ b/test/layoutengine/standard-testcases/page-sequence_language.xml @@ -65,4 +65,10 @@ + + + + + + -- cgit v1.2.3 From 218fa1d72a0f14273d8621047687da7f0ab2b49e Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 17 Apr 2009 13:07:29 +0000 Subject: Enabled support for PDF/A-1a now that we have Tagged PDF, Natural Language Specification and alternate descriptions (fox:alt-text). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@765979 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/pdf/PDFAMode.java | 13 +++++++++- src/java/org/apache/fop/pdf/PDFProfile.java | 29 +++++++++++++++++++--- src/java/org/apache/fop/pdf/PDFRoot.java | 18 +++++++++++++- .../apache/fop/render/pdf/PDFDocumentHandler.java | 11 ++++++-- .../apache/fop/render/pdf/PDFRenderingUtil.java | 7 +++++- 5 files changed, 70 insertions(+), 8 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/pdf/PDFAMode.java b/src/java/org/apache/fop/pdf/PDFAMode.java index 1b433e66d..18c4a2489 100644 --- a/src/java/org/apache/fop/pdf/PDFAMode.java +++ b/src/java/org/apache/fop/pdf/PDFAMode.java @@ -44,7 +44,18 @@ public final class PDFAMode { return this.name; } - /** @return true if this mode obey the restrictions established by PDF/A-1b. */ + /** + * Indicates whether this mode obeys the restrictions established by PDF/A-1a. + * @return true if this mode obeys the restrictions established by PDF/A-1a. + */ + public boolean isPDFA1LevelA() { + return (this != DISABLED); + } + + /** + * Indicates whether this mode obeys the restrictions established by PDF/A-1b. + * @return true if this mode obeys the restrictions established by PDF/A-1b. + */ public boolean isPDFA1LevelB() { return (this != DISABLED); //PDF/A-1a is a superset of PDF/A-1b! diff --git a/src/java/org/apache/fop/pdf/PDFProfile.java b/src/java/org/apache/fop/pdf/PDFProfile.java index 20af4e212..b645cb825 100644 --- a/src/java/org/apache/fop/pdf/PDFProfile.java +++ b/src/java/org/apache/fop/pdf/PDFProfile.java @@ -58,9 +58,6 @@ public class PDFProfile { */ protected void validateProfileCombination() { if (pdfAMode != PDFAMode.DISABLED) { - if (pdfAMode == PDFAMode.PDFA_1A) { - throw new UnsupportedOperationException("PDF/A-1a is not implemented, yet"); - } if (pdfAMode == PDFAMode.PDFA_1B) { if (pdfXMode != PDFXMode.DISABLED && pdfXMode != PDFXMode.PDFX_3_2003) { throw new PDFConformanceException( @@ -192,6 +189,32 @@ public class PDFProfile { } } + /** + * Checks a few things required for tagged PDF. + */ + public void verifyTaggedPDF() { + if (getPDFAMode().isPDFA1LevelA()) { + final String err = "{0} requires the {1} dictionary entry to be set"; + PDFDictionary markInfo = getDocument().getRoot().getMarkInfo(); + if (markInfo == null) { + throw new PDFConformanceException(format( + "{0} requires the MarkInfo dictionary to be present", getPDFAMode())); + } + if (!Boolean.TRUE.equals(markInfo.get("Marked"))) { + throw new PDFConformanceException(format(err, + new Object[] {getPDFAMode(), "Marked"})); + } + if (getDocument().getRoot().getStructTreeRoot() == null) { + throw new PDFConformanceException(format(err, + new Object[] {getPDFAMode(), "StructTreeRoot"})); + } + if (getDocument().getRoot().getLanguage() == null) { + throw new PDFConformanceException(format(err, + new Object[] {getPDFAMode(), "Lang"})); + } + } + } + /** @return true if the ID entry must be present in the trailer. */ public boolean isIDEntryRequired() { return isPDFAActive() || isPDFXActive(); diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java index c8d94585c..3057a9e4d 100644 --- a/src/java/org/apache/fop/pdf/PDFRoot.java +++ b/src/java/org/apache/fop/pdf/PDFRoot.java @@ -19,6 +19,9 @@ package org.apache.fop.pdf; +import java.io.IOException; +import java.io.OutputStream; + /** * Class representing a Root (/Catalog) object. */ @@ -56,7 +59,7 @@ public class PDFRoot extends PDFDictionary { * object must be created before the PDF document is * generated, but it is not assigned an object ID until * it is about to be written (immediately before the xref - * table as part of the trsailer). (mark-fop@inomial.com) + * table as part of the trailer). (mark-fop@inomial.com) * * @param objnum the object's number * @param pages the PDFPages object @@ -68,6 +71,12 @@ public class PDFRoot extends PDFDictionary { setRootPages(pages); } + /** {@inheritDoc} */ + protected int output(OutputStream stream) throws IOException { + getDocument().getProfile().verifyTaggedPDF(); + return super.output(stream); + } + /** * Set the page mode for the PDF document. * @@ -280,4 +289,11 @@ public class PDFRoot extends PDFDictionary { put("MarkInfo", dict); //new PDFMarkInfo() } + /** + * Returns the MarkInfo dictionary. + * @return the MarkInfo dictionary (or null if it's not present) + */ + public PDFDictionary getMarkInfo() { + return (PDFDictionary)get("MarkInfo"); + } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index aba4cceb3..285542635 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -306,8 +306,15 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { if (getUserAgent().isAccessibilityEnabled()) { try { if (this.pdfDoc.getRoot().getLanguage() == null) { - //No language has been set on the first page-sequence, so fall back to "en". - this.pdfDoc.getRoot().setLanguage("en"); + String fallbackLanguage; + if (this.pdfDoc.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"; + } + this.pdfDoc.getRoot().setLanguage(fallbackLanguage); } if (reducedFOTree == null) { diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 2e3c83126..022b7111e 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -37,6 +37,7 @@ import org.apache.xmlgraphics.xmp.Metadata; import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; +import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAMode; @@ -109,7 +110,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants { private void initialize() { PDFEncryptionParams params - = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); + = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); if (params != null) { this.encryptionParams = params; //overwrite if available } @@ -161,6 +162,10 @@ class PDFRenderingUtil implements PDFConfigurationConstants { if (s != null) { this.pdfAMode = PDFAMode.valueOf(s); } + if (this.pdfAMode.isPDFA1LevelA()) { + //Enable accessibility if PDF/A-1a is enabled because it requires tagged PDF. + userAgent.getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); + } s = (String)userAgent.getRendererOptions().get(PDF_X_MODE); if (s != null) { this.pdfXMode = PDFXMode.valueOf(s); -- cgit v1.2.3 From dbaf63a64da3aaa4ecc1dc6de510cca85617a51a Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 22 Sep 2009 11:49:06 +0000 Subject: Factorized into a new class the parsing of the reduced FO tree, that was duplicated in IFSerializer and PDFDocumentHandler. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@817617 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/accessibility/StructureTree.java | 98 ++++++++++++++ .../TransformerNodeEndProcessing.java | 9 +- src/java/org/apache/fop/apps/FOUserAgent.java | 26 ++-- .../fop/render/intermediate/IFSerializer.java | 73 +--------- .../apache/fop/render/pdf/PDFDocumentHandler.java | 149 +++++---------------- 5 files changed, 157 insertions(+), 198 deletions(-) create mode 100644 src/java/org/apache/fop/accessibility/StructureTree.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/StructureTree.java b/src/java/org/apache/fop/accessibility/StructureTree.java new file mode 100644 index 000000000..0be785eb2 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/StructureTree.java @@ -0,0 +1,98 @@ +/* + * 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.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; + } + + /** + * Returns the list of nodes that are the children of the given page sequence. + * + * @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) + "]/*"; + + try { + return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java index 34974233a..c89f72623 100644 --- a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java +++ b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java @@ -28,14 +28,14 @@ import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Templates; import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import org.apache.commons.io.output.ByteArrayOutputStream; - import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; @@ -76,10 +76,9 @@ class TransformerNodeEndProcessing extends TransformerNode { byte[] enrichedFO = enrichedFOBuffer.toByteArray(); Transformer transformer = AccessibilityUtil.getReduceFOTreeTemplates().newTransformer(); Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Result res = new StreamResult(out); + DOMResult res = new DOMResult(); transformer.transform(src, res); - userAgent.setReducedFOTree(out.toByteArray()); + userAgent.setStructureTree(new StructureTree(res.getNode())); SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); saxParserFactory.setNamespaceAware(true); diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 13db8d5ef..0ed5151e0 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -38,6 +38,7 @@ import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.fop.Version; import org.apache.fop.accessibility.AccessibilityUtil; +import org.apache.fop.accessibility.StructureTree; import org.apache.fop.events.DefaultEventBroadcaster; import org.apache.fop.events.Event; import org.apache.fop.events.EventBroadcaster; @@ -100,8 +101,7 @@ public class FOUserAgent { private boolean conserveMemoryPolicy = false; private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster(); - //TODO Verify that a byte array is the best solution here - private byte[] reducedFOTree; // accessibility: reduced FO + private StructureTree structureTree; /** Producer: Metadata element for the system/software that produces * the document. (Some renderers can store this in the document.) @@ -664,20 +664,24 @@ public class FOUserAgent { } /** - * Used for accessibility. Stores the reduced FO tree (the result from the second transform) - * for later use. - * @param reducedFOTree the result from 2nd transform + * Sets the document's structure tree, for use by accessible output formats. + * + * @param structureTree a simplified version of the FO tree, retaining only + * its logical structure */ - public void setReducedFOTree(byte[] reducedFOTree) { - this.reducedFOTree = reducedFOTree; + public void setStructureTree(StructureTree structureTree) { + this.structureTree = structureTree; } /** - * Used for accessibility. Returns the reduced FO tree. - * @return result from 2nd transform as byte array + * Returns the document's structure tree, for use by accessible output + * formats. + * + * @return a simplified version of the FO tree, retaining only its logical + * structure */ - public byte[] getReducedFOTree() { - return this.reducedFOTree; + public StructureTree getStructureTree() { + return this.structureTree; } } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 2d009d58d..281301fbe 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -25,33 +25,22 @@ import java.awt.Paint; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.AffineTransform; -import java.io.ByteArrayInputStream; -import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Stack; -import javax.xml.namespace.NamespaceContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - 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.fonts.FontInfo; import org.apache.fop.render.PrintRendererConfigurator; import org.apache.fop.render.RenderingContext; @@ -76,45 +65,10 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler private IFDocumentHandler mimicHandler; private int pageSequenceCounter; // used for accessibility - private DocumentBuilder parser = null; // used for accessibility - private Document doc = null; // used for accessibility /** Holds the intermediate format state */ private IFState state; - private static class NamespaceContextImpl implements NamespaceContext { - - public String uri; - public 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; - } - - } - /** * Default constructor. */ @@ -202,16 +156,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX, DocumentNavigationExtensionConstants.NAMESPACE); handler.startElement(EL_DOCUMENT); - if (this.getUserAgent().isAccessibilityEnabled()) { - pageSequenceCounter = 0; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - parser = factory.newDocumentBuilder(); - } } catch (SAXException e) { throw new IFException("SAX error in startDocument()", e); - } catch (ParserConfigurationException pce) { - throw new IFException("Error creating new DocumentBuilder", pce); } } @@ -273,18 +219,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addForeignAttributes(atts); handler.startElement(EL_PAGE_SEQUENCE, atts); if (this.getUserAgent().isAccessibilityEnabled()) { - if (doc == null) { - doc = parser.parse( - new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); - } + StructureTree structureTree = getUserAgent().getStructureTree(); handler.startElement(EL_STRUCTURE_TREE); // add structure tree - String xpathExpr - = "/fo:root/fo:page-sequence[" + Integer.toString(++pageSequenceCounter) + "]/*"; - XPath xpath = XPathFactory.newInstance().newXPath(); - NamespaceContext namespaceContext - = new NamespaceContextImpl("fo", "http://www.w3.org/1999/XSL/Format"); - xpath.setNamespaceContext(namespaceContext); - NodeList nodes = (NodeList)xpath.evaluate(xpathExpr, doc, XPathConstants.NODESET); + NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); for (int i = 0, n = nodes.getLength(); i < n; i++) { Node node = nodes.item(i); new DOM2SAX(handler).writeFragment(node); @@ -293,10 +230,6 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } } catch (SAXException e) { throw new IFException("SAX error in startPageSequence()", e); - } catch (XPathExpressionException e) { - throw new IFException("Error while evaluating XPath expression", e); - } catch (IOException ioe) { - throw new IFException("I/O error while parsing structure tree", ioe); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 9e2b2cdb3..064682a3c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -25,31 +25,19 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D.Double; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; -import javax.xml.namespace.NamespaceContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; import org.apache.xmlgraphics.xmp.Metadata; +import org.apache.fop.accessibility.StructureTree; import org.apache.fop.apps.MimeConstants; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAnnotList; @@ -86,8 +74,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** the following variables are used for accessibility */ private int pageSequenceCounter; - private DocumentBuilder parser = null; - private Document reducedFOTree = null; private Map structElemType = new HashMap(); private boolean accessEnabled = false; private int parentTreeKey = -1; @@ -97,41 +83,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { private Map structTreeMap = new HashMap(); private List parentTreeList = new java.util.ArrayList(); - 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; - } - - } - private static final class ParentTreeEntry { private final int position; private final PDFObject object; @@ -233,14 +184,9 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { parentTree = new PDFParentTree(); pageSequenceCounter = 0; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - parser = factory.newDocumentBuilder(); } } catch (IOException e) { throw new IFException("I/O error in startDocument()", e); - } catch (ParserConfigurationException pce) { - throw new IFException("Error creating new DocumentBuilder", pce); } } @@ -271,8 +217,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { parentTree.setNums(nums); getStructTreeRoot().addParentTree(parentTree); pdfDoc.outputTrailer(this.outputStream); - parser = null; - reducedFOTree = null; structElemType = null; parentTree = null; structTreeMap = null; @@ -308,65 +252,46 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } if (getUserAgent().isAccessibilityEnabled()) { - try { - if (this.pdfDoc.getRoot().getLanguage() == null) { - String fallbackLanguage; - if (this.pdfDoc.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"; - } - this.pdfDoc.getRoot().setLanguage(fallbackLanguage); + if (this.pdfDoc.getRoot().getLanguage() == null) { + String fallbackLanguage; + if (this.pdfDoc.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"; } + this.pdfDoc.getRoot().setLanguage(fallbackLanguage); + } - if (reducedFOTree == null) { - reducedFOTree = parser.parse( - new ByteArrayInputStream(this.getUserAgent().getReducedFOTree())); - } - PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); - PDFStructElem structElemPart = new PDFStructElem(parent, - FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); - if (getContext().getLanguage() != null) { - structElemPart.setLanguage(getContext().getLanguage()); - } - this.pdfDoc.assignObjectNumber(structElemPart); - this.pdfDoc.addTrailerObject(structElemPart); - parent.addKid(structElemPart); - - String xpathExpr = "/fo:root/fo:page-sequence[" - + Integer.toString(++pageSequenceCounter) + "]/*"; - XPath xpath = XPathFactory.newInstance().newXPath(); - NamespaceContext namespaceContext = new NamespaceContextImpl("fo", - "http://www.w3.org/1999/XSL/Format"); - xpath.setNamespaceContext(namespaceContext); - - NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, - XPathConstants.NODESET); - - for (int i = 0, n = nodes.getLength(); i < n; i++) { - Node node = nodes.item(i); - if (node.getNodeName().equals("fo:flow") - || node.getNodeName().equals("fo:static-content")) { - PDFStructElem structElemSect = new PDFStructElem(structElemPart, - FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), - structElemPart)); - this.pdfDoc.assignObjectNumber(structElemSect); - this.pdfDoc.addTrailerObject(structElemSect); - structElemPart.addKid(structElemSect); - NodeList iNodes = node.getChildNodes(); - for (int j = 0, m = iNodes.getLength(); j < m; j++) { - processContent(iNodes.item(j), structElemSect, 1); - } + StructureTree structureTree = getUserAgent().getStructureTree(); + PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); + PDFStructElem structElemPart = new PDFStructElem(parent, + FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); + if (getContext().getLanguage() != null) { + structElemPart.setLanguage(getContext().getLanguage()); + } + this.pdfDoc.assignObjectNumber(structElemPart); + this.pdfDoc.addTrailerObject(structElemPart); + parent.addKid(structElemPart); + + NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); + + for (int i = 0, n = nodes.getLength(); i < n; i++) { + Node node = nodes.item(i); + if (node.getNodeName().equals("fo:flow") + || node.getNodeName().equals("fo:static-content")) { + PDFStructElem structElemSect = new PDFStructElem(structElemPart, + FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), + structElemPart)); + this.pdfDoc.assignObjectNumber(structElemSect); + this.pdfDoc.addTrailerObject(structElemSect); + structElemPart.addKid(structElemSect); + NodeList iNodes = node.getChildNodes(); + for (int j = 0, m = iNodes.getLength(); j < m; j++) { + processContent(iNodes.item(j), structElemSect, 1); } } - } catch (SAXException e) { - throw new IFException("SAX error in startPageSequence()", e); - } catch (XPathExpressionException e) { - throw new IFException("Error while evaluating XPath expression", e); - } catch (IOException ioe) { - throw new IFException("I/O error while parsing structure tree", ioe); } } } -- cgit v1.2.3 From 3ec57c684b6564fa7f2c920c32e94572c3543692 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 28 Sep 2009 15:27:30 +0000 Subject: Implemented parsing of structure trees from IF XML files. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@819585 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/accessibility/ParsedStructureTree.java | 95 +++++++++++++++++ .../fop/accessibility/SimpleStructureTree.java | 113 +++++++++++++++++++++ .../apache/fop/accessibility/StructureTree.java | 64 +----------- .../TransformerNodeEndProcessing.java | 2 +- .../apache/fop/render/intermediate/IFParser.java | 75 +++++++++++--- 5 files changed, 271 insertions(+), 78 deletions(-) create mode 100644 src/java/org/apache/fop/accessibility/ParsedStructureTree.java create mode 100644 src/java/org/apache/fop/accessibility/SimpleStructureTree.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java new file mode 100644 index 000000000..69b26c21c --- /dev/null +++ b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java @@ -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); + } + +} diff --git a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java new file mode 100644 index 000000000..e67757207 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java @@ -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(); + } + } + +} diff --git a/src/java/org/apache/fop/accessibility/StructureTree.java b/src/java/org/apache/fop/accessibility/StructureTree.java index 0be785eb2..09a33f151 100644 --- a/src/java/org/apache/fop/accessibility/StructureTree.java +++ b/src/java/org/apache/fop/accessibility/StructureTree.java @@ -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); - } - } } diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java index c89f72623..00d4a5b56 100644 --- a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java +++ b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java @@ -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); diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index e374f82fa..3dc440692 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -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 -- cgit v1.2.3 From 834d6b586229731a5a81c8d8e21a8c40c5d809b5 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 28 Sep 2009 15:35:03 +0000 Subject: Extracted code into new processStructureTree method git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@819591 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/pdf/PDFDocumentHandler.java | 79 ++++++++++++---------- 1 file changed, 42 insertions(+), 37 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 064682a3c..12c796c5a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -252,45 +252,50 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } if (getUserAgent().isAccessibilityEnabled()) { - if (this.pdfDoc.getRoot().getLanguage() == null) { - String fallbackLanguage; - if (this.pdfDoc.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"; - } - this.pdfDoc.getRoot().setLanguage(fallbackLanguage); - } + processStructureTree(); + } + } - StructureTree structureTree = getUserAgent().getStructureTree(); - PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); - PDFStructElem structElemPart = new PDFStructElem(parent, - FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); - if (getContext().getLanguage() != null) { - structElemPart.setLanguage(getContext().getLanguage()); + private void processStructureTree() { + if (this.pdfDoc.getRoot().getLanguage() == null) { + String fallbackLanguage; + if (this.pdfDoc.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"; } - this.pdfDoc.assignObjectNumber(structElemPart); - this.pdfDoc.addTrailerObject(structElemPart); - parent.addKid(structElemPart); - - NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); - - for (int i = 0, n = nodes.getLength(); i < n; i++) { - Node node = nodes.item(i); - if (node.getNodeName().equals("fo:flow") - || node.getNodeName().equals("fo:static-content")) { - PDFStructElem structElemSect = new PDFStructElem(structElemPart, - FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), - structElemPart)); - this.pdfDoc.assignObjectNumber(structElemSect); - this.pdfDoc.addTrailerObject(structElemSect); - structElemPart.addKid(structElemSect); - NodeList iNodes = node.getChildNodes(); - for (int j = 0, m = iNodes.getLength(); j < m; j++) { - processContent(iNodes.item(j), structElemSect, 1); - } + this.pdfDoc.getRoot().setLanguage(fallbackLanguage); + } + + /* Retrieve the structure element of type "Document" */ + PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); + PDFStructElem structElemPart = new PDFStructElem(parent, + FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); + if (getContext().getLanguage() != null) { + structElemPart.setLanguage(getContext().getLanguage()); + } + this.pdfDoc.assignObjectNumber(structElemPart); + this.pdfDoc.addTrailerObject(structElemPart); + parent.addKid(structElemPart); + + StructureTree structureTree = getUserAgent().getStructureTree(); + NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); + + for (int i = 0, n = nodes.getLength(); i < n; i++) { + Node node = nodes.item(i); + if (node.getNodeName().equals("fo:flow") + || node.getNodeName().equals("fo:static-content")) { + PDFStructElem structElemSect = new PDFStructElem(structElemPart, + FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), + structElemPart)); + this.pdfDoc.assignObjectNumber(structElemSect); + this.pdfDoc.addTrailerObject(structElemSect); + structElemPart.addKid(structElemSect); + NodeList iNodes = node.getChildNodes(); + for (int j = 0, m = iNodes.getLength(); j < m; j++) { + processContent(iNodes.item(j), structElemSect, 1); } } } -- cgit v1.2.3 From b59502d64ede1cf0737187a9a50623980668af70 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 7 Oct 2009 17:31:13 +0000 Subject: Fixed support for links and images in the Intermediate Format git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@822808 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/render/intermediate/IFParser.java | 18 ++++++++++++------ .../apache/fop/render/intermediate/IFSerializer.java | 8 ++++++-- .../extensions/DocumentNavigationHandler.java | 9 +++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 3dc440692..da96185bf 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -33,8 +33,6 @@ 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; @@ -43,6 +41,9 @@ 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; @@ -550,8 +551,7 @@ public class IFParser implements IFConstants { s = lastAttributes.getValue("word-spacing"); int wordSpacing = (s != null ? Integer.parseInt(s) : 0); int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx"); - String ptr = lastAttributes.getValue("ptr"); // used for accessibility - establishStructurePointer(ptr); + setAccessibilityPointer(lastAttributes); painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString()); resetStructurePointer(); } @@ -648,8 +648,7 @@ public class IFParser implements IFConstants { int height = Integer.parseInt(lastAttributes.getValue("height")); Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); - String ptr = lastAttributes.getValue("ptr"); // used for accessibility - establishStructurePointer(ptr); + setAccessibilityPointer(lastAttributes); if (foreignObject != null) { painter.drawImage(foreignObject, new Rectangle(x, y, width, height)); @@ -717,6 +716,13 @@ public class IFParser implements IFConstants { return foreignAttributes; } + private void setAccessibilityPointer(Attributes attributes) { + String ptr = attributes.getValue("ptr"); + if (ptr != null && ptr.length() > 0) { + establishStructurePointer(ptr); + } + } + /** {@inheritDoc} */ public void characters(char[] ch, int start, int length) throws SAXException { if (delegate != null) { diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 281301fbe..b010ee41f 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -419,7 +419,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } } - private void addForeignAttributes(AttributesImpl atts) { + private void addForeignAttributes(AttributesImpl atts) throws SAXException { Map foreignAttributes = getContext().getForeignAttributes(); if (!foreignAttributes.isEmpty()) { Iterator iter = foreignAttributes.entrySet().iterator(); @@ -646,7 +646,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } private void addAttribute(AttributesImpl atts, - org.apache.xmlgraphics.util.QName attribute, String value) { + org.apache.xmlgraphics.util.QName attribute, String value) throws SAXException { + handler.startPrefixMapping(attribute.getPrefix(), attribute.getNamespaceURI()); XMLUtil.addAttribute(atts, attribute, value); } @@ -725,6 +726,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler AttributesImpl atts = new AttributesImpl(); atts.addAttribute(null, "rect", "rect", XMLConstants.CDATA, IFUtil.toString(link.getTargetRect())); + if (getUserAgent().isAccessibilityEnabled()) { + addAttribute(atts, "ptr", link.getAction().getPtr()); + } try { handler.startElement(DocumentNavigationExtensionConstants.LINK, atts); serializeXMLizable(link.getAction()); diff --git a/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java b/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java index 376130838..6a27a929d 100644 --- a/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java @@ -48,6 +48,8 @@ public class DocumentNavigationHandler extends DefaultHandler private IFDocumentNavigationHandler navHandler; + private String accessibilityPointer; + /** * Main constructor. * @param navHandler the navigation handler that will receive the events @@ -96,6 +98,7 @@ public class DocumentNavigationHandler extends DefaultHandler throw new SAXException(localName + " must be the root element!"); } Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect"); + accessibilityPointer = attributes.getValue("ptr"); Link link = new Link(null, targetRect); objectStack.push(link); } else if (GOTO_XY.getLocalName().equals(localName)) { @@ -118,6 +121,9 @@ public class DocumentNavigationHandler extends DefaultHandler } action = new GoToXYAction(id, pageIndex, location); } + if (accessibilityPointer != null) { + action.setPtr(accessibilityPointer); + } objectStack.push(action); } else if (GOTO_URI.getLocalName().equals(localName)) { String id = attributes.getValue("id"); @@ -128,6 +134,9 @@ public class DocumentNavigationHandler extends DefaultHandler if (id != null) { action.setID(id); } + if (accessibilityPointer != null) { + action.setPtr(accessibilityPointer); + } objectStack.push(action); } else { throw new SAXException( -- cgit v1.2.3 From 618e88ae22d5371122621e4df84fcbd66bc1ece8 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 7 Oct 2009 17:34:29 +0000 Subject: Removed unnecessary languageStack field git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@822810 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/intermediate/IFSerializer.java | 29 ++++------------------ 1 file changed, 5 insertions(+), 24 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index b010ee41f..9d7c15a61 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -29,7 +29,6 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Stack; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -215,7 +214,11 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (id != null) { atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id); } - applyLanguage(atts); + Locale lang = getContext().getLanguage(); + if (lang != null) { + atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA, + XMLUtil.toRFC3066(lang)); + } addForeignAttributes(atts); handler.startElement(EL_PAGE_SEQUENCE, atts); if (this.getUserAgent().isAccessibilityEnabled()) { @@ -237,7 +240,6 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler public void endPageSequence() throws IFException { try { handler.endElement(EL_PAGE_SEQUENCE); - popLanguage(); } catch (SAXException e) { throw new IFException("SAX error in endPageSequence()", e); } @@ -772,25 +774,4 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler } } - private Stack languageStack = new Stack(); - - private void applyLanguage(AttributesImpl atts) { - Locale lang = getContext().getLanguage(); - if (lang != null) { - if (languageStack.isEmpty() || !languageStack.peek().equals(lang)) { - atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA, - XMLUtil.toRFC3066(lang)); - } - languageStack.push(lang); - } else { - assert languageStack.isEmpty(); - } - } - - private void popLanguage() { - if (!languageStack.isEmpty()) { - languageStack.pop(); - } - } - } -- cgit v1.2.3 From 36243dc349adb041b2eab607f5c5081de4d55542 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 12 Oct 2009 16:26:00 +0000 Subject: Extracted code related to logical structure out of PDFDocumentHandler and put it in its own PDFLogicalStructureHandler class. Vastly simplified the building of the structure tree in the same time. Fixed bug occurring when a block contains only one line of text: the generated PDF was illegal Fixed bug in the generation of the structural parent tree: values in a number tree must be indirect references (note: other number trees in the document may still be wrongly generated) git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824407 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/pdf/PDFDocument.java | 19 ++ src/java/org/apache/fop/pdf/PDFFactory.java | 34 +- src/java/org/apache/fop/pdf/PDFLink.java | 9 +- src/java/org/apache/fop/pdf/PDFNumsArray.java | 22 +- src/java/org/apache/fop/pdf/PDFPage.java | 12 + src/java/org/apache/fop/pdf/PDFStructElem.java | 123 ++++--- src/java/org/apache/fop/pdf/PDFStructTreeRoot.java | 19 +- .../org/apache/fop/render/pdf/FOToPDFRoleMap.java | 3 +- .../apache/fop/render/pdf/PDFDocumentHandler.java | 352 ++------------------- .../render/pdf/PDFDocumentNavigationHandler.java | 5 +- .../fop/render/pdf/PDFLogicalStructureHandler.java | 300 ++++++++++++++++++ src/java/org/apache/fop/render/pdf/PDFPainter.java | 78 ++--- 12 files changed, 482 insertions(+), 494 deletions(-) create mode 100644 src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/pdf/PDFDocument.java b/src/java/org/apache/fop/pdf/PDFDocument.java index 46effdfd6..f0a777bdd 100644 --- a/src/java/org/apache/fop/pdf/PDFDocument.java +++ b/src/java/org/apache/fop/pdf/PDFDocument.java @@ -354,6 +354,25 @@ public class PDFDocument { 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. * diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index db2e99875..a1500c509 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -185,20 +185,12 @@ public class PDFFactory { */ public PDFPage makePage(PDFResources resources, int pageIndex, Rectangle2D mediaBox, Rectangle2D cropBox, - Rectangle2D bleedBox, Rectangle2D trimBox, - int currentPageParentKey) { + Rectangle2D bleedBox, Rectangle2D trimBox) { /* * create a PDFPage with the next object number, the given * resources, contents and dimensions */ PDFPage page = new PDFPage(resources, pageIndex, mediaBox, cropBox, bleedBox, trimBox); - if (currentPageParentKey > -1) { - //Accessibility is enabled - page.setStructParents(currentPageParentKey); - //This is a PDF 1.5 feature. It is set as a work-around for a bug in Adobe Acrobat - //which reports this missing even if the PDF file is PDF 1.4. - page.setTabs(new PDFName("S")); - } getDocument().assignObjectNumber(page); getDocument().getPages().addPage(page); @@ -220,7 +212,7 @@ public class PDFFactory { public PDFPage makePage(PDFResources resources, int pageWidth, int pageHeight, int pageIndex) { Rectangle2D mediaBox = new Rectangle2D.Double(0, 0, pageWidth, pageHeight); - return makePage(resources, pageIndex, mediaBox, mediaBox, mediaBox, mediaBox, -1); + return makePage(resources, pageIndex, mediaBox, mediaBox, mediaBox, mediaBox); } /** @@ -897,15 +889,33 @@ public class PDFFactory { /** * Creates and returns a StructTreeRoot object. Used for accessibility. + * @param parentTree the value of the ParenTree entry * @return structure Tree Root element */ - public PDFStructTreeRoot makeStructTreeRoot() { - PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(); + public PDFStructTreeRoot makeStructTreeRoot(PDFParentTree parentTree) { + PDFStructTreeRoot structTreeRoot = new PDFStructTreeRoot(parentTree); getDocument().assignObjectNumber(structTreeRoot); getDocument().addTrailerObject(structTreeRoot); + getDocument().getRoot().setStructTreeRoot(structTreeRoot); return structTreeRoot; } + /** + * Creates and returns a StructElem object. + * + * @param structureType the structure type of the new element (value for the + * S entry) + * @param parent the parent of the new structure element in the structure + * hierarchy + * @return the newly created element + */ + public PDFStructElem makeStructureElement(PDFName structureType, PDFObject parent) { + PDFStructElem structElem = new PDFStructElem(parent, structureType); + getDocument().assignObjectNumber(structElem); + getDocument().addTrailerObject(structElem); + return structElem; + } + /** * Make a the head object of the name dictionary (the /Dests object). * diff --git a/src/java/org/apache/fop/pdf/PDFLink.java b/src/java/org/apache/fop/pdf/PDFLink.java index 66791e3ba..934932648 100644 --- a/src/java/org/apache/fop/pdf/PDFLink.java +++ b/src/java/org/apache/fop/pdf/PDFLink.java @@ -71,11 +71,12 @@ public class PDFLink extends PDFObject { /** - * Used for accessibility - * @param mcid of this structParent + * Sets the value of the StructParent entry for this link. + * + * @param structParent key in the structure parent tree */ - public void setStructParent(int mcid) { - this.structParent = new Integer(mcid); + public void setStructParent(int structParent) { + this.structParent = new Integer(structParent); } /** diff --git a/src/java/org/apache/fop/pdf/PDFNumsArray.java b/src/java/org/apache/fop/pdf/PDFNumsArray.java index e1c38dd48..6db7b02ac 100644 --- a/src/java/org/apache/fop/pdf/PDFNumsArray.java +++ b/src/java/org/apache/fop/pdf/PDFNumsArray.java @@ -52,13 +52,31 @@ public class PDFNumsArray extends PDFObject { return this.map.size(); } + /** + * Sets an entry. + * @param key the key of the value to set + * @param obj the new value + */ + public void put(Integer key, Object obj) { + this.map.put(key, obj); + } + /** * Sets an entry. * @param key the key of the value to set * @param obj the new value */ public void put(int key, Object obj) { - this.map.put(new Integer(key), obj); + put(new Integer(key), obj); + } + + /** + * Gets an entry. + * @param key the key of requested value + * @return the requested value + */ + public Object get(Integer key) { + return this.map.get(key); } /** @@ -67,7 +85,7 @@ public class PDFNumsArray extends PDFObject { * @return the requested value */ public Object get(int key) { - return this.map.get(new Integer(key)); + return get(new Integer(key)); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/pdf/PDFPage.java b/src/java/org/apache/fop/pdf/PDFPage.java index 1bcaa65c6..7a5365761 100644 --- a/src/java/org/apache/fop/pdf/PDFPage.java +++ b/src/java/org/apache/fop/pdf/PDFPage.java @@ -160,6 +160,18 @@ public class PDFPage extends PDFResourceContext { */ public void setStructParents(int structParents) { put("StructParents", structParents); + //This is a PDF 1.5 feature. It is set as a work-around for a bug in Adobe Acrobat + //which reports this missing even if the PDF file is PDF 1.4. + setTabs(new PDFName("S")); + } + + /** + * Returns the value of the StructParents entry. + * + * @return the StructParents value, null if the entry has not been set + */ + public Integer getStructParents() { + return (Integer) get("StructParents"); } /** diff --git a/src/java/org/apache/fop/pdf/PDFStructElem.java b/src/java/org/apache/fop/pdf/PDFStructElem.java index 2f8898a19..4fb8cbcd5 100644 --- a/src/java/org/apache/fop/pdf/PDFStructElem.java +++ b/src/java/org/apache/fop/pdf/PDFStructElem.java @@ -28,53 +28,34 @@ import org.apache.fop.util.XMLUtil; */ public class PDFStructElem extends PDFDictionary { - private PDFObject parentObject = null; - private boolean level1 = false; + private PDFStructElem parentElement; /** - * Create the /StructTreeRoot dictionary - * @param parent Parent of this PDFStructElem - * @param structureType the structure type for the element + * Creates a new structure element. + * + * @param parent parent of this element + * @param structureType the structure type of this element */ - public PDFStructElem(PDFObject parent, PDFName structureType) { - super(); + PDFStructElem(PDFObject parent, PDFName structureType) { if (parent instanceof PDFStructElem) { - parentObject = (PDFStructElem) parent; + parentElement = (PDFStructElem) parent; } put("Type", new PDFName("StructElem")); - setStructureType(structureType); + put("S", structureType); setParent(parent); } /** - * This method is called for PDFStructElements which are direct children of - * fo:static-content or fo:flow-section - */ - public void setLevel1() { - this.level1 = true; - } - - /** + * Returns the parent of this structure element. * - * @return true if the PDFStructElement is a direct child of - * fo:static-content or fo:flow-section - */ - public boolean getLevel1() { - return this.level1; - } - - /** - * Get the parent - * @return PDFStructElem of parent + * @return the parent, null if the parent is not a structure + * element (i.e., is the structure tree root) */ - public PDFObject getParentStructElem() { - return (PDFStructElem)this.parentObject; + public PDFStructElem getParentStructElem() { + return parentElement; } - /** - * Set the parent for this StructElem - * @param parent to be added - */ + /** {@inheritDoc} */ public void setParent(PDFObject parent) { if (parent != null) { put("P", new PDFReference(parent)); @@ -82,16 +63,20 @@ public class PDFStructElem extends PDFDictionary { } /** - * The kids of this StructElem - * @return the kids + * Returns the kids of this structure element. + * + * @return the value of the K entry */ - public PDFArray getKids() { - return (PDFArray)get("K"); + private PDFArray getKids() { + return (PDFArray) get("K"); } /** - * Add a kid to this strucElem - * @param kid to be added + * Add a kid to this structure element. This element will then add itself to + * its parent structure element if it has not already, and so will the + * parent, and so on. + * + * @param kid element to be added */ public void addKid(PDFObject kid) { PDFArray kids = getKids(); @@ -100,50 +85,46 @@ public class PDFStructElem extends PDFDictionary { put("K", kids); } kids.add(kid); + joinHierarchy(); } - /** - * Add a kid, but only if it does not already exist. - * @param kid to be added - * @return true if kid did not already exist - */ - public boolean addUniqueKid(PDFObject kid) { - PDFArray mArray = getKids(); - if (mArray == null || !mArray.contains(kid)) { - addKid(kid); - return true; - } else { - return false; - } + private boolean containsKid(PDFObject kid) { + PDFArray kids = getKids(); + return kids != null && kids.contains(kid); } - /** - * Add kid referenced through mcid integer. Used for images. - * @param mcid of this kid - */ - public void addMCIDKid(int mcid) { - put("K", mcid); + private void joinHierarchy() { + if (parentElement != null && !parentElement.containsKid(this)) { + parentElement.addKid(this); + } } /** - * Add a page reference to this structElem - * @param pageObject to be added + * Sets the given mcid as the kid of this structure element. This element + * will then add itself to its parent structure element if it has not + * already, and so will the parent, and so on. + * + * @param mcid mcid of the marked-content sequence corresponding to this + * structure element's kid */ - public void addPage(Object pageObject) { - put("Pg", (PDFObject) pageObject); + public void setMCIDKid(int mcid) { + put("K", mcid); + joinHierarchy(); } /** - * Sets the structure type (the "S" entry). - * @param type the structure type + * Sets the page reference of this structure element. + * + * @param page value for the Pg entry */ - public void setStructureType(PDFName type) { - put("S", type); + public void setPage(PDFPage page) { + put("Pg", page); } /** * Returns the structure type of this structure element. - * @return the structure type + * + * @return the value of the S entry */ public PDFName getStructureType() { return (PDFName)get("S"); @@ -154,13 +135,14 @@ public class PDFStructElem extends PDFDictionary { * @param language the language (as defined in the section about * "Natural Language Specification") */ - public void setLanguage(String language) { + private void setLanguage(String language) { put("Lang", language); } /** * Sets the language of this structure element. - * @param language the language + * + * @param language a value for the Lang entry */ public void setLanguage(Locale language) { setLanguage(XMLUtil.toRFC3066(language)); @@ -168,7 +150,8 @@ public class PDFStructElem extends PDFDictionary { /** * Returns the language of this structure element. - * @return the language (or null if no language was specified) + * + * @return the value of the Lang entry (null if no language was specified) */ public String getLanguage() { return (String)get("Lang"); diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java index e530b1582..0840c7a4b 100644 --- a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java +++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java @@ -26,18 +26,11 @@ public class PDFStructTreeRoot extends PDFDictionary { /** * Create the /StructTreeRoot dictionary. + * @param parentTree the value of the ParenTree entry */ - public PDFStructTreeRoot() { - super(); + PDFStructTreeRoot(PDFParentTree parentTree) { put("Type", new PDFName("StructTreeRoot")); put("K", new PDFArray()); - } - - /** - * Add parentTree entry. - * @param parentTree to be added - */ - public void addParentTree(PDFParentTree parentTree) { put("ParentTree", parentTree); } @@ -49,14 +42,6 @@ public class PDFStructTreeRoot extends PDFDictionary { return (PDFArray)get("K"); } - /** - * Returns the first child of the kids array (normally the structure tree root element) - * @return the first child - */ - public PDFObject getFirstChild() { - return (PDFObject)getKids().get(0); - } - /** * Adds a kid. * @param kid to be added diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java index f0cc39698..e3122ec39 100644 --- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java +++ b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java @@ -28,7 +28,7 @@ import org.apache.fop.pdf.PDFStructElem; /** * This class provides the standard mappings from Formatting Objects to PDF structure types. */ -public class FOToPDFRoleMap { +public final class FOToPDFRoleMap { private static final Map STANDARD_MAPPINGS = new java.util.HashMap(); @@ -138,4 +138,5 @@ public class FOToPDFRoleMap { } + private FOToPDFRoleMap() { } } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index 12c796c5a..fab7f8403 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -26,34 +26,23 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D.Double; import java.io.IOException; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import org.w3c.dom.NodeList; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import org.apache.xmlgraphics.xmp.Metadata; -import org.apache.fop.accessibility.StructureTree; import org.apache.fop.apps.MimeConstants; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAnnotList; -import org.apache.fop.pdf.PDFArray; -import org.apache.fop.pdf.PDFDictionary; import org.apache.fop.pdf.PDFDocument; -import org.apache.fop.pdf.PDFName; -import org.apache.fop.pdf.PDFNumsArray; -import org.apache.fop.pdf.PDFObject; import org.apache.fop.pdf.PDFPage; -import org.apache.fop.pdf.PDFParentTree; import org.apache.fop.pdf.PDFReference; import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; -import org.apache.fop.pdf.PDFStructElem; -import org.apache.fop.pdf.PDFStructTreeRoot; import org.apache.fop.render.extensions.prepress.PageBoundaries; import org.apache.fop.render.extensions.prepress.PageScale; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; @@ -72,32 +61,11 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** logging instance */ private static Log log = LogFactory.getLog(PDFDocumentHandler.class); - /** the following variables are used for accessibility */ - private int pageSequenceCounter; - private Map structElemType = new HashMap(); - private boolean accessEnabled = false; - private int parentTreeKey = -1; - private int pageLinkCount = 0; - private int mcidKey = -1; - private PDFParentTree parentTree = null; - private Map structTreeMap = new HashMap(); - private List parentTreeList = new java.util.ArrayList(); - - private static final class ParentTreeEntry { - private final int position; - private final PDFObject object; - private ParentTreeEntry(int p, PDFObject o) { - position = p; - object = o; - } - private int getPosition() { - return position; - } - private PDFObject getPDFObject() { - return object; - } - } + private int pageSequenceNumber; + private boolean accessEnabled; + + private PDFLogicalStructureHandler logicalStructureHandler; /** the PDF Document being created */ protected PDFDocument pdfDoc; @@ -165,6 +133,10 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { return this.pdfUtil; } + PDFLogicalStructureHandler getLogicalStructureHandler() { + return logicalStructureHandler; + } + /** {@inheritDoc} */ public void startDocument() throws IFException { super.startDocument(); @@ -172,18 +144,8 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream); this.accessEnabled = getUserAgent().isAccessibilityEnabled(); if (accessEnabled) { - this.pdfDoc.getRoot().makeTagged(); - log.info("Accessibility is enabled"); - PDFStructTreeRoot structTreeRoot = this.pdfDoc.getFactory().makeStructTreeRoot(); - this.pdfDoc.getRoot().setStructTreeRoot(structTreeRoot); - PDFStructElem structElemDocument = new PDFStructElem(structTreeRoot, - FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot)); - this.pdfDoc.assignObjectNumber(structElemDocument); - this.pdfDoc.addTrailerObject(structElemDocument); - structTreeRoot.addKid(structElemDocument); - - parentTree = new PDFParentTree(); - pageSequenceCounter = 0; + pdfDoc.getRoot().makeTagged(); + logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc); } } catch (IOException e) { throw new IFException("I/O error in startDocument()", e); @@ -199,31 +161,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { public void endDocument() throws IFException { try { pdfDoc.getResources().addFonts(pdfDoc, fontInfo); - if (getUserAgent().isAccessibilityEnabled()) { - PDFNumsArray nums = parentTree.getNums(); - for (int i = 0; i <= this.parentTreeKey; i++) { - PDFArray tArray = new PDFArray(); - for (int j = 0; j < parentTreeList.size(); j++) { - if (((ParentTreeEntry)parentTreeList.get(j)).getPosition() == i) { - tArray.add(((ParentTreeEntry)parentTreeList.get(j)).getPDFObject()); - } - } - if (tArray.length() == 1) { - nums.put(i, tArray.get(0)); - } else if (tArray.length() > 1) { - nums.put(i, tArray); - } - } - parentTree.setNums(nums); - getStructTreeRoot().addParentTree(parentTree); - pdfDoc.outputTrailer(this.outputStream); - structElemType = null; - parentTree = null; - structTreeMap = null; - parentTreeList = null; - } else { - pdfDoc.outputTrailer(this.outputStream); - } + pdfDoc.outputTrailer(this.outputStream); this.pdfDoc = null; pdfResources = null; @@ -236,11 +174,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { super.endDocument(); } - private PDFStructTreeRoot getStructTreeRoot() { - return this.pdfDoc.getRoot().getStructTreeRoot(); - } - - /** {@inheritDoc} */ public void startPageSequence(String id) throws IFException { //TODO page sequence title @@ -251,53 +184,10 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { this.pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(getContext().getLanguage())); } - if (getUserAgent().isAccessibilityEnabled()) { - processStructureTree(); - } - } - - private void processStructureTree() { - if (this.pdfDoc.getRoot().getLanguage() == null) { - String fallbackLanguage; - if (this.pdfDoc.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"; - } - this.pdfDoc.getRoot().setLanguage(fallbackLanguage); - } - - /* Retrieve the structure element of type "Document" */ - PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild(); - PDFStructElem structElemPart = new PDFStructElem(parent, - FOToPDFRoleMap.mapFormattingObject("page-sequence", parent)); - if (getContext().getLanguage() != null) { - structElemPart.setLanguage(getContext().getLanguage()); - } - this.pdfDoc.assignObjectNumber(structElemPart); - this.pdfDoc.addTrailerObject(structElemPart); - parent.addKid(structElemPart); - - StructureTree structureTree = getUserAgent().getStructureTree(); - NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); - - for (int i = 0, n = nodes.getLength(); i < n; i++) { - Node node = nodes.item(i); - if (node.getNodeName().equals("fo:flow") - || node.getNodeName().equals("fo:static-content")) { - PDFStructElem structElemSect = new PDFStructElem(structElemPart, - FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), - structElemPart)); - this.pdfDoc.assignObjectNumber(structElemSect); - this.pdfDoc.addTrailerObject(structElemSect); - structElemPart.addKid(structElemSect); - NodeList iNodes = node.getChildNodes(); - for (int j = 0, m = iNodes.getLength(); j < m; j++) { - processContent(iNodes.item(j), structElemSect, 1); - } - } + if (accessEnabled) { + NodeList nodes = getUserAgent().getStructureTree().getPageSequence( + ++pageSequenceNumber); + logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage()); } } @@ -309,11 +199,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public void startPage(int index, String name, String pageMasterName, Dimension size) throws IFException { - // used for accessibility - this.parentTreeKey = this.parentTreeKey + this.pageLinkCount + 1; - this.mcidKey = 0; - this.pageLinkCount = 0; - // this.pdfResources = this.pdfDoc.getResources(); PageBoundaries boundaries = new PageBoundaries(size, getContext().getForeignAttributes()); @@ -340,8 +225,10 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { toPointAndScale(mediaBox, scaleX, scaleY), toPointAndScale(cropBox, scaleX, scaleY), toPointAndScale(bleedBox, scaleX, scaleY), - toPointAndScale(trimBox, scaleX, scaleY), - parentTreeKey); + toPointAndScale(trimBox, scaleX, scaleY)); + if (accessEnabled) { + logicalStructureHandler.startPage(currentPage); + } pdfUtil.generatePageLabel(index, name); @@ -366,7 +253,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public IFPainter startPageContent() throws IFException { - return new PDFPainter(this); + return new PDFPainter(this, logicalStructureHandler); } /** {@inheritDoc} */ @@ -376,6 +263,9 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** {@inheritDoc} */ public void endPage() throws IFException { + if (accessEnabled) { + logicalStructureHandler.endPage(); + } try { this.documentNavigationHandler.commit(); this.pdfDoc.registerObject(generator.getStream()); @@ -429,196 +319,4 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } } - /** - * Used for accessibility - * @param position in parentTree - * @param o reference of PDFObject to be added to parentTree - */ - void addToParentTree(int position, PDFObject o) { - PDFNumsArray nums = parentTree.getNums(); - nums.put(position, o); - parentTree.setNums(nums); - } - - - /** - * Used for accessibility - * @param position in parentTree - * @param o object to be added to parentTree - */ - void addToTempList(int position, PDFObject o) { - ParentTreeEntry myEntry = new ParentTreeEntry(position, o); - this.parentTreeList.add(myEntry); - } - - - /** - * Return the PDFObject - * @param ptr this is the key - * @return PDFObject referenced with ptr - */ - PDFObject getTrailerObject(String ptr) { - return (PDFObject) this.structTreeMap.get(ptr); - } - - /** - * Return the parent PDFObject referenced by ptr - * @param ptr this is the key - * @return PDFObject parent of PDFObject referenced with ptr - */ - PDFObject getParentTrailerObject(String ptr) { - PDFStructElem tempStructElem = (PDFStructElem) this.structTreeMap.get(ptr); - return tempStructElem.getParentStructElem(); - } - - /** - * Adds a link object as child to StructElem - * @param ptr of PDFStructElem - * @param o PDFLink object - */ - void addLinkToStructElem(String ptr, PDFObject o) { - PDFDictionary dict = new PDFDictionary(); - dict.put("Type", new PDFName("OBJR")); - dict.put("Pg", this.currentPage); - dict.put("Obj", o); - PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); - tempStructElem.addKid(dict); - } - - /** - * Adds a child to StructElem, called from PDFPainter.drawImage - * @param ptr of PDFStructElem - * @param mcid sequence number within page - */ - void addChildToStructElemImage(String ptr, int mcid) { - PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); - tempStructElem.addMCIDKid(mcid); - tempStructElem.addPage(this.currentPage); - if (!tempStructElem.getLevel1()) { - addMeToParent(tempStructElem); - } - } - - /** - * Adds a child to StructElem, called from PDFPainter.drawText - * @param ptr of PDFSturctElem - * @param mcid sequence number within page - */ - void addChildToStructElemText(String ptr, int mcid) { - PDFStructElem tempStructElem = (PDFStructElem) structTreeMap.get(ptr); - if (tempStructElem != null) { - PDFDictionary dict = new PDFDictionary(); - dict.put("Type", new PDFName("MCR")); - dict.put("Pg", this.currentPage); - dict.put("MCID", mcid); - tempStructElem.addKid(dict); - if (!tempStructElem.getLevel1()) { - addMeToParent(tempStructElem); - } - } - //tempStructElem is null, for example inside fo:leaders in which case - //the text shall be marked as artifact - } - - /** - * Add child PDFStructElem to parent child elements - * Repeat until level 1 or child already exists - * @param childStructElem to be added - */ - protected void addMeToParent(PDFStructElem childStructElem) { - PDFStructElem parentStructElem = (PDFStructElem) childStructElem.getParentStructElem(); - // test if child already exists or not - if (parentStructElem.addUniqueKid(childStructElem)) { - if (!parentStructElem.getLevel1()) { - addMeToParent(parentStructElem); - } - } - } - - /** - * increment MCID value - */ - void incMCID() { - this.mcidKey++; - } - - /** - * MCID is a sequential number per page - * @return MCID value - */ - int getMCID() { - return this.mcidKey; - } - - /** - * Used for accessibility - * @param ptr pointer into map of all structElems - * @return type of found structElem - */ - String getStructElemType(String ptr) { - return (String) structElemType.get(ptr); - } - - /** - * Used for accessibility - * @param me node being processed - * @param parent parent node in DOM of me - * @param depth depth level in DOM, static-content & flow are 0 - */ - private void processContent(Node me, PDFStructElem parent, int depth) { - String ptr; - Node attr = me.getAttributes().getNamedItem("foi:ptr"); - if (attr != null) { - ptr = attr.getNodeValue(); - } else { - log.error("Accessibility: missing foi:ptr"); - ptr = ""; - } - String s = me.getLocalName(); - PDFStructElem structElem = new PDFStructElem(parent, - FOToPDFRoleMap.mapFormattingObject(s, parent)); - this.pdfDoc.assignObjectNumber(structElem); - this.pdfDoc.addTrailerObject(structElem); - if (depth == 1) { - parent.addKid(structElem); - structElem.setLevel1(); - } - if (s.equals("external-graphic") || s.equals("instream-foreign-object")) { - Node altTextNode = me.getAttributes().getNamedItem("fox:alt-text"); - if (altTextNode != null) { - structElem.put("Alt", altTextNode.getNodeValue()); - } else { - log.warn("fo:" + s - + " requires an alternative text attribute fox:alt-text for accessibility"); - structElem.put("Alt", "No alternate text specified"); - } - } - // the following map is used e.g. in PDFPainter.drawText - structElemType.put(ptr, structElem.get("S").toString()); - // this map will be used for fast access of the StructElem by ptr - structTreeMap.put(ptr, structElem); - NodeList nodes = me.getChildNodes(); - depth++; - for (int i = 0, n = nodes.getLength(); i < n; i++) { - processContent(nodes.item(i), structElem, depth); - } - } - - /** - * used for accessibility - * @return mcid to be used for next link to be processed - */ - int getPageLinkCountPlusPageParentKey() { - this.pageLinkCount++; - return (this.parentTreeKey + this.pageLinkCount); - } - - /** - * used for accessibility - * @return current parentTreeKey - */ - int getCurrentParentTreeKey() { - return this.parentTreeKey; - } - } diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index 138129334..2407e0dd2 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -117,10 +117,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler //accessibility: ptr has a value String ptr = link.getAction().getPtr(); if (ptr != null && ptr.length() > 0) { - this.documentHandler.addLinkToStructElem(ptr, pdfLink); - int id = this.documentHandler.getPageLinkCountPlusPageParentKey(); - pdfLink.setStructParent(id); - this.documentHandler.addToParentTree(id, pdfLink ); + documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr); } documentHandler.currentPage.addAnnotation(pdfLink); } diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java new file mode 100644 index 000000000..e1f1fae68 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java @@ -0,0 +1,300 @@ +/* + * 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.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.apache.fop.pdf.PDFArray; +import org.apache.fop.pdf.PDFDictionary; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFLink; +import org.apache.fop.pdf.PDFName; +import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFParentTree; +import org.apache.fop.pdf.PDFStructElem; +import org.apache.fop.pdf.PDFStructTreeRoot; + + +/** + * Handles the creation of the logical structure in the PDF document. + */ +class PDFLogicalStructureHandler { + + private static final PDFName MCR = new PDFName("MCR"); + + private static final PDFName OBJR = new PDFName("OBJR"); + + private static final MarkedContentInfo ARTIFACT = new MarkedContentInfo(null, -1, null); + + private final PDFDocument pdfDoc; + + /** + * Map of references to the corresponding structure elements. + */ + private final Map structTreeMap = new HashMap(); + + private final PDFParentTree parentTree = new PDFParentTree(); + + private int parentTreeKey; + + private PDFPage currentPage; + + /** + * The array of references, from marked-content sequences in the current + * page, to their parent structure elements. This will be a value in the + * structure parent tree, whose corresponding key will be the page's + * StructParents entry. + */ + private PDFArray pageParentTreeArray; + + private PDFStructElem rootStructureElement; + + /** + * Class providing the necessary information for bracketing content + * associated to a structure element as a marked-content sequence. + */ + static final class MarkedContentInfo { + + /** + * A value that can be used for the tag operand of a marked-content + * operator. This is the structure type of the corresponding structure + * element. + */ + final String tag; + + /** + * The value for the MCID entry of the marked-content sequence's property list. + */ + final int mcid; + + private final PDFStructElem parent; + + private MarkedContentInfo(String tag, int mcid, PDFStructElem parent) { + this.tag = tag; + this.mcid = mcid; + this.parent = parent; + } + } + + /** + * Creates a new instance for handling the logical structure of the given document. + * + * @param pdfDoc a document + */ + PDFLogicalStructureHandler(PDFDocument pdfDoc) { + this.pdfDoc = pdfDoc; + 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 structElemPart = pdfDoc.getFactory().makeStructureElement( + FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement), + rootStructureElement); + rootStructureElement.addKid(structElemPart); + if (language != null) { + structElemPart.setLanguage(language); + } + + for (int i = 0, n = structureTree.getLength(); i < n; i++) { + Node node = structureTree.item(i); + if (node.getNodeName().equals("fo:flow") + || node.getNodeName().equals("fo: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) { + Node attr = node.getAttributes().getNamedItem("foi:ptr"); + assert attr != null; + String ptr = attr.getNodeValue(); + String nodeName = node.getLocalName(); + PDFStructElem structElem = pdfDoc.getFactory().makeStructureElement( + FOToPDFRoleMap.mapFormattingObject(nodeName, parent), 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); + } + if (nodeName.equals("external-graphic") || nodeName.equals("instream-foreign-object")) { + Node altTextNode = node.getAttributes().getNamedItem("fox:alt-text"); + if (altTextNode != null) { + structElem.put("Alt", altTextNode.getNodeValue()); + } else { + // TODO route that to event notification system +// log.warn("fo:" + s +// + " requires an alternative text attribute fox:alt-text for accessibility"); + structElem.put("Alt", "No alternate text specified"); + } + } + structTreeMap.put(ptr, structElem); + NodeList nodes = node.getChildNodes(); + for (int i = 0, n = nodes.getLength(); i < n; i++) { + processNode(nodes.item(i), structElem, false); + } + } + + private int getNextParentTreeKey() { + return parentTreeKey++; + } + + /** + * Receive notification of the beginning of a new page. + * + * @param page the page that will be rendered in PDF + */ + void startPage(PDFPage page) { + currentPage = page; + currentPage.setStructParents(getNextParentTreeKey()); + pageParentTreeArray = new PDFArray(); + } + + /** + * Receive notification of the end of the current page. + */ + void endPage() { + // TODO + // Values in a number tree must be indirect references to the PDF + // objects associated to the keys. To enforce that the array is + // registered to the PDF document. Unfortunately that can't be done + // earlier since a call to PDFContentGenerator.flushPDFDoc can be made + // before the array is complete, which would result in only part of it + // being output to the PDF. + // This should really be handled by PDFNumsArray + pdfDoc.registerObject(pageParentTreeArray); + parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray); + } + + private MarkedContentInfo addToParentTree(String reference) { + PDFStructElem parent = (PDFStructElem) structTreeMap.get(reference); + if (parent == null) { + return ARTIFACT; + } else { + pageParentTreeArray.add(parent); + String type = parent.getStructureType().toString(); + int mcid = pageParentTreeArray.length() - 1; + return new MarkedContentInfo(type, mcid, parent); + } + } + + /** + * Adds a content item corresponding to text into the structure tree, if + * there is a structure element associated to it. + * + * @param parentReference reference to the parent structure element of the + * piece of text + * @return the necessary information for bracketing the content as a + * marked-content sequence. If there is no element in the structure tree + * associated to that content, returns an instance whose + * {@link MarkedContentInfo#tag} value is null. The content + * must then be treated as an artifact. + */ + MarkedContentInfo addTextContentItem(String parentReference) { + MarkedContentInfo mci = addToParentTree(parentReference); + if (mci != ARTIFACT) { + PDFDictionary contentItem = new PDFDictionary(); + contentItem.put("Type", MCR); + contentItem.put("Pg", this.currentPage); + contentItem.put("MCID", mci.mcid); + mci.parent.addKid(contentItem); + } + return mci; + } + + /** + * Adds a content item corresponding to an image into the structure tree, if + * there is a structure element associated to it. + * + * @param parentReference reference to the parent structure element of the + * image + * @return the necessary information for bracketing the content as a + * marked-content sequence. If there is no element in the structure tree + * associated to that image, returns an instance whose + * {@link MarkedContentInfo#tag} value is null. The image + * must then be treated as an artifact. + */ + MarkedContentInfo addImageContentItem(String parentReference) { + MarkedContentInfo mci = addToParentTree(parentReference); + if (mci != ARTIFACT) { + mci.parent.setMCIDKid(mci.mcid); + mci.parent.setPage(this.currentPage); + } + return mci; + } + + // While the PDF spec allows images to be referred as PDF objects, this + // makes the Acrobat Pro checker complain that the image is not accessible. + // Its alt-text is still read aloud though. Using marked-content sequences + // like for text works. +// MarkedContentInfo addImageObject(String parentReference) { +// MarkedContentInfo mci = addToParentTree(parentReference); +// if (mci != ARTIFACT) { +// PDFDictionary contentItem = new PDFDictionary(); +// contentItem.put("Type", OBJR); +// contentItem.put("Pg", this.currentPage); +// contentItem.put("Obj", null); +// mci.parent.addKid(contentItem); +// } +// return mci; +// } + + /** + * Adds a content item corresponding to the given link into the structure + * tree. + * + * @param link a link + * @param reference reference to the corresponding parent structure element + */ + void addLinkContentItem(PDFLink link, String reference) { + int structParent = getNextParentTreeKey(); + link.setStructParent(structParent); + parentTree.getNums().put(structParent, link); + PDFDictionary contentItem = new PDFDictionary(); + contentItem.put("Type", OBJR); + contentItem.put("Pg", this.currentPage); + contentItem.put("Obj", link); + PDFStructElem parent = (PDFStructElem) structTreeMap.get(reference); + parent.addKid(contentItem); + } + +} diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 4c9baf0f6..4b9f47a4e 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -29,9 +29,6 @@ import java.io.IOException; import org.w3c.dom.Document; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; @@ -47,6 +44,7 @@ import org.apache.fop.render.intermediate.AbstractIFPainter; import org.apache.fop.render.intermediate.IFContext; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.CharUtilities; @@ -56,9 +54,6 @@ import org.apache.fop.util.CharUtilities; */ public class PDFPainter extends AbstractIFPainter { - /** logging instance */ - private static Log log = LogFactory.getLog(PDFPainter.class); - private final PDFDocumentHandler documentHandler; /** The current content generator */ @@ -66,19 +61,22 @@ public class PDFPainter extends AbstractIFPainter { private final PDFBorderPainter borderPainter; - private boolean accessEnabled = false; + private boolean accessEnabled; - private int mcid; // used for accessibility + private MarkedContentInfo imageMCI; - private String structElemType; // used for accessibility + private PDFLogicalStructureHandler logicalStructureHandler; /** * Default constructor. * @param documentHandler the parent document handler + * @param logicalStructureHandler the logical structure handler */ - public PDFPainter(PDFDocumentHandler documentHandler) { + public PDFPainter(PDFDocumentHandler documentHandler, + PDFLogicalStructureHandler logicalStructureHandler) { super(); this.documentHandler = documentHandler; + this.logicalStructureHandler = logicalStructureHandler; this.generator = documentHandler.generator; this.borderPainter = new PDFBorderPainter(this.generator); this.state = IFState.create(); @@ -137,52 +135,29 @@ public class PDFPainter extends AbstractIFPainter { String ptr = getContext().getStructurePointer(); prepareImageMCID(ptr); placeImageAccess(rect, xobject); - addImageMCID(ptr); } else { placeImage(rect, xobject); } - return; - } - if (accessEnabled && getContext().hasStructurePointer()) { - String ptr = getContext().getStructurePointer(); - prepareImageMCID(ptr); - drawImageUsingURI(uri, rect); - addImageMCID(ptr); } else { + if (accessEnabled && getContext().hasStructurePointer()) { + String ptr = getContext().getStructurePointer(); + prepareImageMCID(ptr); + } drawImageUsingURI(uri, rect); + flushPDFDoc(); } - flushPDFDoc(); } private void prepareImageMCID(String ptr) { - mcid = this.documentHandler.getMCID(); - mcid++; // fix for Acro Checker - this.documentHandler.incMCID(); // simulating a parent text element - structElemType = this.documentHandler.getStructElemType(ptr); - if (structElemType != null) { - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getParentTrailerObject(ptr)); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getTrailerObject(ptr)); - } - } - - private void addImageMCID(String ptr) { - if (this.structElemType != null) { - this.documentHandler.addChildToStructElemImage(ptr, mcid); - this.documentHandler.incMCID(); - } - //If structElemType is null, it means "Artifact" mode (ex. leader with use-content). + imageMCI = logicalStructureHandler.addImageContentItem(ptr); } /** {@inheritDoc} */ protected RenderingContext createRenderingContext() { PDFRenderingContext pdfContext = new PDFRenderingContext( getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); - pdfContext.setMCID(mcid); - pdfContext.setStructElemType(structElemType); + pdfContext.setMCID(imageMCI.mcid); + pdfContext.setStructElemType(imageMCI.tag); return pdfContext; } @@ -212,7 +187,7 @@ public class PDFPainter extends AbstractIFPainter { * @param xobj the image XObject */ private void placeImageAccess(Rectangle rect, PDFXObject xobj) { - generator.saveGraphicsState(structElemType, mcid); + generator.saveGraphicsState(imageMCI.tag, imageMCI.mcid); generator.add(format(rect.width) + " 0 0 " + format(-rect.height) + " " + format(rect.x) + " " @@ -226,11 +201,8 @@ public class PDFPainter extends AbstractIFPainter { if (accessEnabled && getContext().hasStructurePointer()) { String ptr = getContext().getStructurePointer(); prepareImageMCID(ptr); - drawImageUsingDocument(doc, rect); - addImageMCID(ptr); - } else { - drawImageUsingDocument(doc, rect); } + drawImageUsingDocument(doc, rect); flushPDFDoc(); } @@ -326,21 +298,13 @@ public class PDFPainter extends AbstractIFPainter { throws IFException { if (accessEnabled) { String ptr = getContext().getStructurePointer(); - int mcId; - String structElType = null; if (ptr != null && ptr.length() > 0) { - mcId = this.documentHandler.getMCID(); - structElType = this.documentHandler.getStructElemType(ptr); - this.documentHandler.addToTempList( - this.documentHandler.getCurrentParentTreeKey(), - this.documentHandler.getTrailerObject(ptr)); + MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr); if (generator.getTextUtil().isInTextObject()) { - generator.separateTextElements(mcId, structElType); + generator.separateTextElements(mci.mcid, mci.tag); } generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObjectAccess(mcId, structElType); - this.documentHandler.addChildToStructElemText(ptr, mcId); - this.documentHandler.incMCID(); + generator.beginTextObjectAccess(mci.mcid, mci.tag); } else { // // Leader content is marked as "/Artifact" -- cgit v1.2.3 From 73c1cddb3208d994cb209e83ae101e0d4b1e9413 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 12 Oct 2009 17:39:53 +0000 Subject: Switched parameters of separateTextElements and beginTextObjectAccess, for consistency with saveGraphicsState and beginMarkedContentSequence git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824439 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/pdf/PDFContentGenerator.java | 12 ++++++------ src/java/org/apache/fop/render/pdf/PDFPainter.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 73e1945f2..9cff94f6a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -219,10 +219,10 @@ public class PDFContentGenerator { /** * used for accessibility, separates 2 text elements - * @param mcid of new text element * @param structElemType of parent of new text element + * @param mcid of new text element */ - protected void separateTextElements(int mcid, String structElemType) { + protected void separateTextElements(String structElemType, int mcid) { textutil.endTextObject(); endMarkedContentSequence(); beginMarkedContentSequence(structElemType, mcid); @@ -235,7 +235,7 @@ public class PDFContentGenerator { */ public void separateTextElementFromLeader() { if (!inArtifactMode) { - separateTextElements(0, null); + separateTextElements(null, 0); } } @@ -248,10 +248,10 @@ public class PDFContentGenerator { /** * Accessibility beginTextObject - * @param mcid of text element * @param structElemType of parent + * @param mcid of text element */ - protected void beginTextObjectAccess(int mcid, String structElemType) { + protected void beginTextObjectAccess(String structElemType, int mcid) { if (!textutil.isInTextObject()) { beginMarkedContentSequence(structElemType, mcid); textutil.beginTextObject(); @@ -262,7 +262,7 @@ public class PDFContentGenerator { * Accessibility begin of LeaderTextObject */ public void beginLeaderTextObject() { - beginTextObjectAccess(0, null); + beginTextObjectAccess(null, 0); } /** Indicates the end of a text object. */ diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 4b9f47a4e..25e169ab0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -301,10 +301,10 @@ public class PDFPainter extends AbstractIFPainter { if (ptr != null && ptr.length() > 0) { MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr); if (generator.getTextUtil().isInTextObject()) { - generator.separateTextElements(mci.mcid, mci.tag); + generator.separateTextElements(mci.tag, mci.mcid); } generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObjectAccess(mci.mcid, mci.tag); + generator.beginTextObjectAccess(mci.tag, mci.mcid); } else { // // Leader content is marked as "/Artifact" -- cgit v1.2.3 From 9198590b5929ad49312ac8ab18f725a465634ad9 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 12 Oct 2009 17:44:44 +0000 Subject: Implemented accessibility in PDFRenderer git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824441 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/pdf/PDFContentGenerator.java | 2 +- .../org/apache/fop/render/pdf/PDFRenderer.java | 91 ++++++++++++++++++++-- 2 files changed, 84 insertions(+), 9 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 9cff94f6a..942d5c72c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -183,7 +183,7 @@ public class PDFContentGenerator { this.inMarkedContentSequence = true; } - private void endMarkedContentSequence() { + void endMarkedContentSequence() { currentStream.add("EMC\n"); this.inMarkedContentSequence = false; this.inArtifactMode = false; diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 3b737150b..4da0330c5 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -31,8 +31,12 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageInfo; @@ -61,6 +65,7 @@ import org.apache.fop.area.inline.InlineParent; 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.Viewport; import org.apache.fop.area.inline.WordArea; import org.apache.fop.datatypes.URISpecification; import org.apache.fop.events.ResourceEventProducer; @@ -91,9 +96,11 @@ import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.RendererContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; import org.apache.fop.traits.RuleStyle; import org.apache.fop.util.AbstractPaintingState; import org.apache.fop.util.CharUtilities; +import org.apache.fop.util.XMLUtil; import org.apache.fop.util.AbstractPaintingState.AbstractData; /** @@ -127,7 +134,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf * this is used for prepared pages that cannot be immediately * rendered */ - protected Map pages = null; + private Map pages; /** * Maps unique PageViewport key to PDF page reference @@ -193,6 +200,14 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf /** Image handler registry */ private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry(); + private boolean accessEnabled; + + private PDFLogicalStructureHandler logicalStructureHandler; + + private int pageSequenceNumber; + + /** Reference in the structure tree to the image being rendered. */ + private String imageReference; /** * create the PDF renderer @@ -204,6 +219,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf public void setUserAgent(FOUserAgent agent) { super.setUserAgent(agent); this.pdfUtil = new PDFRenderingUtil(getUserAgent()); + accessEnabled = agent.isAccessibilityEnabled(); } PDFRenderingUtil getPDFUtil() { @@ -225,6 +241,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } ostream = stream; this.pdfDoc = pdfUtil.setupPDFDocument(stream); + if (accessEnabled) { + pdfDoc.getRoot().makeTagged(); + logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc); + } } /** @@ -274,8 +294,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf * {@inheritDoc} */ public boolean supportsOutOfOrder() { - //return false; - return true; + return !accessEnabled; } /** @@ -394,17 +413,25 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf info.setTitle(str); } } + Locale language = null; if (pageSequence.getLanguage() != null) { String lang = pageSequence.getLanguage(); String country = pageSequence.getCountry(); - String langCode = lang + (country != null ? "-" + country : ""); + if (lang != null) { + language = (country == null) ? new Locale(lang) : new Locale(lang, country); + } if (pdfDoc.getRoot().getLanguage() == null) { //Only set if not set already (first non-null is used) //Note: No checking is performed whether the values are valid! - pdfDoc.getRoot().setLanguage(langCode); + pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(language)); } } pdfUtil.generateDefaultXMPMetadata(); + if (accessEnabled) { + NodeList nodes = getUserAgent().getStructureTree().getPageSequence( + ++pageSequenceNumber); + logicalStructureHandler.processStructureTree(nodes, language); + } } /** @@ -457,6 +484,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } currentPageRef = currentPage.referencePDF(); + if (accessEnabled) { + logicalStructureHandler.startPage(currentPage); + } + Rectangle bounds = page.getViewArea(); pageHeight = bounds.height; @@ -474,6 +505,10 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf super.renderPage(page); + if (accessEnabled) { + logicalStructureHandler.endPage(); + } + this.pdfDoc.registerObject(generator.getStream()); currentPage.setContents(generator.getStream()); PDFAnnotList annots = currentPage.getAnnotations(); @@ -903,11 +938,21 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf + pdfDoc.getProfile()); } else if (action != null) { PDFLink pdfLink = factory.makeLink(ipRect, action); + if (accessEnabled) { + String ptr = (String) ip.getTrait(Trait.PTR); + logicalStructureHandler.addLinkContentItem(pdfLink, ptr); + } currentPage.addAnnotation(pdfLink); } } } + /** {@inheritDoc} */ + public void renderViewport(Viewport viewport) { + imageReference = (String) viewport.getTrait(Trait.PTR); + super.renderViewport(viewport); + } + private Typeface getTypeface(String fontName) { Typeface tf = (Typeface) fontInfo.getFonts().get(fontName); if (tf instanceof LazyFont) { @@ -922,7 +967,16 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf Color ct = (Color) text.getTrait(Trait.COLOR); updateColor(ct, true); - beginTextObject(); + if (accessEnabled) { + String ptr = (String) text.getTrait(Trait.PTR); + MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr); + if (generator.getTextUtil().isInTextObject()) { + generator.separateTextElements(mci.tag, mci.mcid); + } + generator.beginTextObjectAccess(mci.tag, mci.mcid); + } else { + beginTextObject(); + } String fontName = getInternalFontNameForArea(text); int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue(); @@ -1178,13 +1232,22 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf * @param xobj the image XObject */ public void placeImage(float x, float y, float w, float h, PDFXObject xobj) { - saveGraphicsState(); + if (accessEnabled) { + MarkedContentInfo mci = logicalStructureHandler.addImageContentItem(imageReference); + generator.saveGraphicsState(mci.tag, mci.mcid); + } else { + saveGraphicsState(); + } generator.add(format(w) + " 0 0 " + format(-h) + " " + format(currentIPPosition / 1000f + x) + " " + format(currentBPPosition / 1000f + h + y) + " cm\n" + xobj.getName() + " Do\n"); - restoreGraphicsState(); + if (accessEnabled) { + generator.restoreGraphicsStateAccess(); + } else { + restoreGraphicsState(); + } } /** {@inheritDoc} */ @@ -1205,6 +1268,18 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf return context; } + /** {@inheritDoc} */ + public void renderDocument(Document doc, String ns, Rectangle2D pos, Map foreignAttributes) { + if (accessEnabled) { + MarkedContentInfo mci = logicalStructureHandler.addImageContentItem(imageReference); + generator.beginMarkedContentSequence(mci.tag, mci.mcid); + } + super.renderDocument(doc, ns, pos, foreignAttributes); + if (accessEnabled) { + generator.endMarkedContentSequence(); + } + } + /** * Render leader area. * This renders a leader area which is an area with a rule. -- cgit v1.2.3 From 1958fe771925a5c9f64c29580eb11fe42d46f16a Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 12 Oct 2009 18:04:07 +0000 Subject: Reset imageReference once it's no longer needed git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824444 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/pdf/PDFRenderer.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 4da0330c5..17ab1755c 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -951,6 +951,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf public void renderViewport(Viewport viewport) { imageReference = (String) viewport.getTrait(Trait.PTR); super.renderViewport(viewport); + imageReference = null; } private Typeface getTypeface(String fontName) { -- cgit v1.2.3 From e3e19e881a5cd78c2d4612bb01310cc3500cc2ca Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 13 Oct 2009 15:34:29 +0000 Subject: Bugfix: render all background images as artifacts git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824808 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/intermediate/IFContext.java | 9 ----- .../apache/fop/render/pdf/PDFContentGenerator.java | 10 ------ .../fop/render/pdf/PDFImageHandlerRawJPEG.java | 10 ++---- .../render/pdf/PDFImageHandlerRenderedImage.java | 6 ++-- .../apache/fop/render/pdf/PDFImageHandlerSVG.java | 6 ++-- src/java/org/apache/fop/render/pdf/PDFPainter.java | 29 +++++----------- .../apache/fop/render/pdf/PDFRenderingContext.java | 39 ++++------------------ 7 files changed, 24 insertions(+), 85 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/intermediate/IFContext.java b/src/java/org/apache/fop/render/intermediate/IFContext.java index f052846d3..804b353c1 100644 --- a/src/java/org/apache/fop/render/intermediate/IFContext.java +++ b/src/java/org/apache/fop/render/intermediate/IFContext.java @@ -155,13 +155,4 @@ public class IFContext { return this.structurePointer; } - /** - * Indicates whether a structure pointer is available. - * @return true if there's a structure pointer - * @see #setStructurePointer(String) - */ - public boolean hasStructurePointer() { - return (this.structurePointer != null) && (structurePointer.length() > 0); - } - } diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index 942d5c72c..51a74bd2b 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -229,16 +229,6 @@ public class PDFContentGenerator { textutil.beginTextObject(); } - /** - * used for accessibility - * separates a text element from fo:leader text element - */ - public void separateTextElementFromLeader() { - if (!inArtifactMode) { - separateTextElements(null, 0); - } - } - /** Indicates the beginning of a text object. */ protected void beginTextObject() { if (!textutil.isInTextObject()) { diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java index fe3a00aa8..02dd98ecf 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java @@ -34,6 +34,7 @@ import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; /** * Image handler implementation which handles raw JPEG images for PDF output. @@ -83,13 +84,8 @@ public class PDFImageHandlerRawJPEG implements PDFImageHandler, ImageHandler { float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; if (context.getUserAgent().isAccessibilityEnabled()) { - String structElemType = pdfContext.getStructElemType(); - if (structElemType != null && structElemType.length() > 0) { - int sequenceNum = pdfContext.getSequenceNum(); - generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); - } else { - generator.placeImage(x, y, w, h, xobj); - } + MarkedContentInfo mci = pdfContext.getMarkedContentInfo(); + generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid); } else { generator.placeImage(x, y, w, h, xobj); } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java index 24d17a2b1..3c02cb6f3 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java @@ -34,6 +34,7 @@ import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; /** * Image handler implementation which handles RenderedImage instances for PDF output. @@ -84,9 +85,8 @@ public class PDFImageHandlerRenderedImage implements PDFImageHandler, ImageHandl float w = (float)pos.getWidth() / 1000f; float h = (float)pos.getHeight() / 1000f; if (context.getUserAgent().isAccessibilityEnabled()) { - String structElemType = pdfContext.getStructElemType(); - int sequenceNum = pdfContext.getSequenceNum(); - generator.placeImage(x, y, w, h, xobj, structElemType, sequenceNum); + MarkedContentInfo mci = pdfContext.getMarkedContentInfo(); + generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid); } else { generator.placeImage(x, y, w, h, xobj); } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java index fde9e0696..e6d2c8a71 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java @@ -40,6 +40,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.image.loader.batik.BatikImageFlavors; import org.apache.fop.render.ImageHandler; import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; import org.apache.fop.svg.PDFAElementBridge; import org.apache.fop.svg.PDFBridgeContext; import org.apache.fop.svg.PDFGraphics2D; @@ -122,9 +123,8 @@ public class PDFImageHandlerSVG implements ImageHandler { generator.comment("SVG setup"); generator.saveGraphicsState(); if (context.getUserAgent().isAccessibilityEnabled()) { - String structElemType = pdfContext.getStructElemType(); - int sequenceNum = pdfContext.getSequenceNum(); - generator.beginMarkedContentSequence(structElemType, sequenceNum); + MarkedContentInfo mci = pdfContext.getMarkedContentInfo(); + generator.beginMarkedContentSequence(mci.tag, mci.mcid); } generator.setColor(Color.black, false); generator.setColor(Color.black, true); diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 25e169ab0..2ae28b6db 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -131,7 +131,7 @@ public class PDFPainter extends AbstractIFPainter { throws IFException { PDFXObject xobject = getPDFDoc().getXObject(uri); if (xobject != null) { - if (accessEnabled && getContext().hasStructurePointer()) { + if (accessEnabled) { String ptr = getContext().getStructurePointer(); prepareImageMCID(ptr); placeImageAccess(rect, xobject); @@ -139,7 +139,7 @@ public class PDFPainter extends AbstractIFPainter { placeImage(rect, xobject); } } else { - if (accessEnabled && getContext().hasStructurePointer()) { + if (accessEnabled) { String ptr = getContext().getStructurePointer(); prepareImageMCID(ptr); } @@ -156,8 +156,7 @@ public class PDFPainter extends AbstractIFPainter { protected RenderingContext createRenderingContext() { PDFRenderingContext pdfContext = new PDFRenderingContext( getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo()); - pdfContext.setMCID(imageMCI.mcid); - pdfContext.setStructElemType(imageMCI.tag); + pdfContext.setMarkedContentInfo(imageMCI); return pdfContext; } @@ -198,7 +197,7 @@ public class PDFPainter extends AbstractIFPainter { /** {@inheritDoc} */ public void drawImage(Document doc, Rectangle rect) throws IFException { - if (accessEnabled && getContext().hasStructurePointer()) { + if (accessEnabled) { String ptr = getContext().getStructurePointer(); prepareImageMCID(ptr); } @@ -298,22 +297,12 @@ public class PDFPainter extends AbstractIFPainter { throws IFException { if (accessEnabled) { String ptr = getContext().getStructurePointer(); - if (ptr != null && ptr.length() > 0) { - MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr); - if (generator.getTextUtil().isInTextObject()) { - generator.separateTextElements(mci.tag, mci.mcid); - } - generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObjectAccess(mci.tag, mci.mcid); - } else { - // - // Leader content is marked as "/Artifact" - if (generator.getTextUtil().isInTextObject()) { - generator.separateTextElementFromLeader(); - } - generator.updateColor(state.getTextColor(), true, null); - generator.beginLeaderTextObject(); + MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr); + if (generator.getTextUtil().isInTextObject()) { + generator.separateTextElements(mci.tag, mci.mcid); } + generator.updateColor(state.getTextColor(), true, null); + generator.beginTextObjectAccess(mci.tag, mci.mcid); } else { generator.updateColor(state.getTextColor(), true, null); generator.beginTextObject(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java index f82019b4a..80adfa5c8 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java @@ -25,6 +25,7 @@ import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fonts.FontInfo; import org.apache.fop.pdf.PDFPage; import org.apache.fop.render.AbstractRenderingContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; /** * Rendering context for PDF production. @@ -34,11 +35,7 @@ public class PDFRenderingContext extends AbstractRenderingContext { private PDFContentGenerator generator; private FontInfo fontInfo; private PDFPage page; - /** Temp. val. for accessibility, used in PDFImageHandlerRenderedImage */ - private String structElemType = ""; - - /** Temp. val. for accessibility, used in PDFImageHandlerRenderedImage */ - private int mcid = -1; + private MarkedContentInfo mci; /** * Main constructor. @@ -84,35 +81,11 @@ public class PDFRenderingContext extends AbstractRenderingContext { return this.fontInfo; } - /** - * Used for accessibility, used in PDFPainter.drawImage - * @param value to be stored - */ - public void setMCID(int value) { - mcid = value; - } - - /** - * Used for accessibility - * @return mcid - */ - public int getSequenceNum() { - return mcid; + void setMarkedContentInfo(MarkedContentInfo mci) { + this.mci = mci; } - /** - * Used for accessibility - * @param s the type of the structure element - */ - public void setStructElemType(String s) { - structElemType = s; - } - - /** - * Used for accessibility - * @return the type of the structure element - */ - public String getStructElemType() { - return structElemType; + MarkedContentInfo getMarkedContentInfo() { + return mci; } } -- cgit v1.2.3 From d3551e5d341ef9ef2ba2091dd9aa91c279bd9515 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 13 Oct 2009 16:14:12 +0000 Subject: Implemented rendering of structure tree to Area Tree XML and parsing back from it git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824827 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/accessibility/ParsedStructureTree.java | 31 ++++++++ src/java/org/apache/fop/area/AreaTreeParser.java | 82 ++++++++++++++++++---- .../org/apache/fop/render/xml/XMLRenderer.java | 22 +++++- 3 files changed, 122 insertions(+), 13 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java index 69b26c21c..3aa95b627 100644 --- a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java +++ b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java @@ -19,13 +19,20 @@ 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.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; import org.w3c.dom.NodeList; import org.xml.sax.ContentHandler; @@ -92,4 +99,28 @@ public class ParsedStructureTree implements StructureTree { return (NodeList) pageSequenceStructures.get(number - 1); } + /** + * Returns an XML-like representation of the structure trees. + *

+ * Note: use only for debugging purpose, as this method + * performs non-trivial operations. + *

+ * @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(); + } + } + } diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index 25d110086..12e31530d 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -39,8 +39,6 @@ import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; -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; @@ -50,12 +48,16 @@ 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.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.util.QName; +import org.apache.fop.accessibility.ParsedStructureTree; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.area.Trait.Background; import org.apache.fop.area.Trait.InternalLink; @@ -84,6 +86,7 @@ import org.apache.fop.util.ContentHandlerFactory; 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; @@ -157,6 +160,26 @@ public class AreaTreeParser { private Locator locator; + 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(); + startAreaTreeElement("pageSequence", pageSequenceAttributes); + } + } + public Handler(AreaTreeModel treeModel, FOUserAgent userAgent, ElementMappingRegistry elementMappingRegistry) { this.treeModel = treeModel; @@ -193,6 +216,10 @@ public class AreaTreeParser { makers.put("bookmarkTree", new BookmarkTreeMaker()); makers.put("bookmark", new BookmarkMaker()); makers.put("destination", new DestinationMaker()); + if (userAgent.isAccessibilityEnabled()) { + structureTree = new ParsedStructureTree(tFactory); + userAgent.setStructureTree(structureTree); + } } private Area findAreaType(Class clazz) { @@ -266,19 +293,22 @@ public class AreaTreeParser { delegate.startDocument(); delegate.startElement(uri, localName, qName, attributes); } else { - lastAttributes = new AttributesImpl(attributes); boolean handled = true; if ("".equals(uri)) { - Maker maker = (Maker)makers.get(localName); - content.clear(); - ignoreCharacters = true; - if (maker != null) { - ignoreCharacters = maker.ignoreCharacters(); - maker.startElement(attributes); - } else if ("extension-attachments".equals(localName)) { - //TODO implement me + if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) { + structureTreeBuilder = new StructureTreeBuilder(attributes, structureTree); + } else if (localName.equals("structureTree")) { + if (userAgent.isAccessibilityEnabled()) { + delegate = structureTreeBuilder; + } else { + /* Delegate to a handler that does nothing */ + delegate = new DefaultHandler(); + } + delegateStack.push(qName); + delegate.startDocument(); + delegate.startElement(uri, localName, qName, attributes); } else { - handled = false; + handled = startAreaTreeElement(localName, attributes); } } else { ContentHandlerFactoryRegistry registry @@ -305,6 +335,23 @@ public class AreaTreeParser { } } + private boolean startAreaTreeElement(String localName, Attributes attributes) + throws SAXException { + lastAttributes = new AttributesImpl(attributes); + Maker maker = (Maker)makers.get(localName); + content.clear(); + ignoreCharacters = true; + if (maker != null) { + ignoreCharacters = maker.ignoreCharacters(); + maker.startElement(attributes); + } else if ("extension-attachments".equals(localName)) { + //TODO implement me + } else { + return false; + } + return true; + } + /** {@inheritDoc} */ public void endElement(String uri, String localName, String qName) throws SAXException { if (delegate != null) { @@ -701,6 +748,7 @@ public class AreaTreeParser { setTraits(attributes, ip, SUBSET_BOX); setTraits(attributes, ip, SUBSET_COLOR); setTraits(attributes, ip, SUBSET_LINK); + setPtr(ip, attributes); Area parent = (Area)areaStack.peek(); parent.addChildArea(ip); areaStack.push(ip); @@ -749,6 +797,7 @@ public class AreaTreeParser { "tlsadjust", 0)); text.setTextWordSpaceAdjust(XMLUtil.getAttributeAsInt(attributes, "twsadjust", 0)); + setPtr(text, attributes); Area parent = (Area)areaStack.peek(); parent.addChildArea(text); areaStack.push(text); @@ -841,6 +890,7 @@ public class AreaTreeParser { viewport.setContentPosition(XMLUtil.getAttributeAsRectangle2D(attributes, "pos")); viewport.setClip(XMLUtil.getAttributeAsBoolean(attributes, "clip", false)); viewport.setOffset(XMLUtil.getAttributeAsInt(attributes, "offset", 0)); + setPtr(viewport, attributes); Area parent = (Area)areaStack.peek(); parent.addChildArea(viewport); areaStack.push(viewport); @@ -859,6 +909,7 @@ public class AreaTreeParser { transferForeignObjects(attributes, image); setAreaAttributes(attributes, image); setTraits(attributes, image, SUBSET_COMMON); + setPtr(image, attributes); getCurrentViewport().setContent(image); } } @@ -1143,6 +1194,13 @@ public class AreaTreeParser { } } + private void setPtr(Area area, Attributes attributes) { + String ptr = attributes.getValue("ptr"); + if (ptr != null) { + area.addTrait(Trait.PTR, ptr); + } + } + /** {@inheritDoc} */ public void characters(char[] ch, int start, int length) throws SAXException { if (delegate != null) { diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index 8e8ae3f1d..d86814d25 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -34,12 +34,14 @@ import javax.xml.transform.sax.TransformerHandler; 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.xmlgraphics.util.XMLizable; +import org.apache.fop.accessibility.StructureTree; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; @@ -86,6 +88,7 @@ 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. @@ -105,6 +108,8 @@ public class XMLRenderer extends AbstractXMLRenderer { /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ protected Renderer mimic; + private int pageSequenceNumber; + /** * Creates a new XML renderer. */ @@ -440,6 +445,21 @@ public class XMLRenderer extends AbstractXMLRenderer { } transferForeignObjects(pageSequence); startElement("pageSequence", atts); + if (this.getUserAgent().isAccessibilityEnabled()) { + StructureTree structureTree = getUserAgent().getStructureTree(); + String structureTreeElement = "structureTree"; + startElement(structureTreeElement); + NodeList nodes = structureTree.getPageSequence(++pageSequenceNumber); + 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); + } + } + endElement(structureTreeElement); + } handleExtensionAttachments(pageSequence.getExtensionAttachments()); LineArea seqTitle = pageSequence.getTitle(); if (seqTitle != null) { -- cgit v1.2.3 From 928e650d8c781448ca2c18cb74908592dcadf0bb Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Tue, 13 Oct 2009 17:13:39 +0000 Subject: Re-format addPtr.xsl to make it readable. Also add a ptr attribute to fo:table-and-caption and fo:table-caption, even if they are not supported, in order to avoid a crash. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@824845 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/accessibility/addPtr.xsl | 55 ++++++++++++++++++------ 1 file changed, 43 insertions(+), 12 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/addPtr.xsl b/src/java/org/apache/fop/accessibility/addPtr.xsl index f619817cd..35645906a 100644 --- a/src/java/org/apache/fop/accessibility/addPtr.xsl +++ b/src/java/org/apache/fop/accessibility/addPtr.xsl @@ -16,15 +16,46 @@ limitations under the License. --> - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From a3960ce47f877ae7c9d767dc3804be1bc4ffae24 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 15 Oct 2009 10:47:34 +0000 Subject: Made the structure tree processing chain more robust by removing any assumption about prefix names for namespaces. Avoid warnings issued by reduceFOTree.xsl when FO file contains foreign elements (like MathML). SimpleStructureTree: replaced XPath query with simple DOM method calls. Cleaned up, simplified and re-organized reduceFOTree and addPtr stylesheets. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@825461 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/accessibility/ParsedStructureTree.java | 2 +- .../fop/accessibility/SimpleStructureTree.java | 55 +------- src/java/org/apache/fop/accessibility/addPtr.xsl | 57 +++++--- .../org/apache/fop/accessibility/reduceFOTree.xsl | 146 +++++++++++---------- .../fop/render/pdf/PDFLogicalStructureHandler.java | 26 ++-- 5 files changed, 141 insertions(+), 145 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java index 3aa95b627..646496252 100644 --- a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java +++ b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java @@ -82,7 +82,7 @@ public class ParsedStructureTree implements StructureTree { public void characters(char[] ch, int start, int length) throws SAXException { /* - * There's not text node in the structure tree. This is just + * There's no text node in the structure tree. This is just * whitespace => ignore */ } diff --git a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java index e67757207..c009b7b30 100644 --- a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java +++ b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java @@ -21,17 +21,11 @@ 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; @@ -45,57 +39,16 @@ 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); - } + Node pageSequence = reducedFOTree.getFirstChild().getChildNodes().item(number - 1); + assert pageSequence.getNodeType() == Node.ELEMENT_NODE + && pageSequence.getLocalName().equals("page-sequence"); + return pageSequence.getChildNodes(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/accessibility/addPtr.xsl b/src/java/org/apache/fop/accessibility/addPtr.xsl index 35645906a..b3984d426 100644 --- a/src/java/org/apache/fop/accessibility/addPtr.xsl +++ b/src/java/org/apache/fop/accessibility/addPtr.xsl @@ -20,42 +20,69 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:foi="http://xmlgraphics.apache.org/fop/internal"> + + + + + + + + + + + + - + + + - + + - + + - + + + - + + - + + + - + + + - - - - - - - - + + + + + + + + + + + + diff --git a/src/java/org/apache/fop/accessibility/reduceFOTree.xsl b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl index 84c500639..8e9bcfc13 100644 --- a/src/java/org/apache/fop/accessibility/reduceFOTree.xsl +++ b/src/java/org/apache/fop/accessibility/reduceFOTree.xsl @@ -16,71 +16,85 @@ limitations under the License. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" + xmlns:foi="http://xmlgraphics.apache.org/fop/internal"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java index e1f1fae68..2313431f0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java @@ -26,6 +26,8 @@ import java.util.Map; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +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; @@ -129,22 +131,21 @@ class PDFLogicalStructureHandler { for (int i = 0, n = structureTree.getLength(); i < n; i++) { Node node = structureTree.item(i); - if (node.getNodeName().equals("fo:flow") - || node.getNodeName().equals("fo: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); - } + 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) { - Node attr = node.getAttributes().getNamedItem("foi:ptr"); + Node attr = node.getAttributes().getNamedItemNS(InternalElementMapping.URI, "ptr"); assert attr != null; String ptr = attr.getNodeValue(); String nodeName = node.getLocalName(); @@ -157,7 +158,8 @@ class PDFLogicalStructureHandler { parent.addKid(structElem); } if (nodeName.equals("external-graphic") || nodeName.equals("instream-foreign-object")) { - Node altTextNode = node.getAttributes().getNamedItem("fox:alt-text"); + Node altTextNode = node.getAttributes().getNamedItemNS( + ExtensionElementMapping.URI, "alt-text"); if (altTextNode != null) { structElem.put("Alt", altTextNode.getNodeValue()); } else { -- cgit v1.2.3 From 113a028123216ba7f6d6c376d0b7b0a9f76986bd Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 15 Oct 2009 14:25:28 +0000 Subject: Merged SimpleStructureTree and ParsedStructureTree classes into a single one, used by both TransformerNodeEndProcessing and intermediate XML parsers git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@825504 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/accessibility/ParsedStructureTree.java | 126 --------------------- .../fop/accessibility/SimpleStructureTree.java | 66 ----------- .../apache/fop/accessibility/StructureTree.java | 70 +++++++++++- .../fop/accessibility/StructureTreeBuilder.java | 95 ++++++++++++++++ .../TransformerNodeEndProcessing.java | 11 +- src/java/org/apache/fop/area/AreaTreeParser.java | 23 ++-- .../apache/fop/render/intermediate/IFParser.java | 22 ++-- .../fop/render/intermediate/IFSerializer.java | 4 +- .../apache/fop/render/pdf/PDFDocumentHandler.java | 5 +- .../org/apache/fop/render/pdf/PDFRenderer.java | 5 +- .../org/apache/fop/render/xml/XMLRenderer.java | 6 +- 11 files changed, 202 insertions(+), 231 deletions(-) delete mode 100644 src/java/org/apache/fop/accessibility/ParsedStructureTree.java delete mode 100644 src/java/org/apache/fop/accessibility/SimpleStructureTree.java create mode 100644 src/java/org/apache/fop/accessibility/StructureTreeBuilder.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java b/src/java/org/apache/fop/accessibility/ParsedStructureTree.java deleted file mode 100644 index 646496252..000000000 --- a/src/java/org/apache/fop/accessibility/ParsedStructureTree.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.TransformerConfigurationException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.sax.TransformerHandler; -import javax.xml.transform.stream.StreamResult; - -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 no 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); - } - - /** - * Returns an XML-like representation of the structure trees. - *

- * Note: use only for debugging purpose, as this method - * performs non-trivial operations. - *

- * @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(); - } - } - -} diff --git a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java b/src/java/org/apache/fop/accessibility/SimpleStructureTree.java deleted file mode 100644 index c009b7b30..000000000 --- a/src/java/org/apache/fop/accessibility/SimpleStructureTree.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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 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 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; - - SimpleStructureTree(Node reducedFOTree) { - this.reducedFOTree = reducedFOTree; - } - - /** {@inheritDoc} */ - public NodeList getPageSequence(int number) { - Node pageSequence = reducedFOTree.getFirstChild().getChildNodes().item(number - 1); - assert pageSequence.getNodeType() == Node.ELEMENT_NODE - && pageSequence.getLocalName().equals("page-sequence"); - return pageSequence.getChildNodes(); - } - - /** {@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(); - } - } - -} diff --git a/src/java/org/apache/fop/accessibility/StructureTree.java b/src/java/org/apache/fop/accessibility/StructureTree.java index 09a33f151..a0fdaac21 100644 --- a/src/java/org/apache/fop/accessibility/StructureTree.java +++ b/src/java/org/apache/fop/accessibility/StructureTree.java @@ -19,20 +19,84 @@ 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 interface StructureTree { +public final class StructureTree { + + private final List pageSequenceStructures = new ArrayList(); + + /** + * Package-private default constructor. + */ + 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 number number of the page sequence, 1-based + * @param index index of the page sequence, 0-based * @return its children nodes */ - NodeList getPageSequence(int number); + public NodeList getPageSequence(int index) { + return (NodeList) pageSequenceStructures.get(index); + } + + /** + * Returns an XML-like representation of the structure trees. + *

+ * Note: use only for debugging purpose, as this method + * performs non-trivial operations. + *

+ * @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(); + } + } } diff --git a/src/java/org/apache/fop/accessibility/StructureTreeBuilder.java b/src/java/org/apache/fop/accessibility/StructureTreeBuilder.java new file mode 100644 index 000000000..cd9aa011a --- /dev/null +++ b/src/java/org/apache/fop/accessibility/StructureTreeBuilder.java @@ -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 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()); + } + }; + } + +} diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java index 00d4a5b56..36f36fdef 100644 --- a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java +++ b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java @@ -32,10 +32,12 @@ import javax.xml.transform.dom.DOMResult; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import org.apache.commons.io.output.ByteArrayOutputStream; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import org.apache.commons.io.output.ByteArrayOutputStream; + import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; @@ -78,7 +80,12 @@ class TransformerNodeEndProcessing extends TransformerNode { Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); DOMResult res = new DOMResult(); transformer.transform(src, res); - userAgent.setStructureTree(new SimpleStructureTree(res.getNode())); + StructureTree structureTree = new StructureTree(); + NodeList pageSequences = res.getNode().getFirstChild().getChildNodes(); + for (int i = 0; i < pageSequences.getLength(); i++) { + structureTree.addPageSequenceStructure(pageSequences.item(i).getChildNodes()); + } + userAgent.setStructureTree(structureTree); SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); saxParserFactory.setNamespaceAware(true); diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index 12e31530d..784ca0684 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -57,7 +57,7 @@ import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.util.QName; -import org.apache.fop.accessibility.ParsedStructureTree; +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; @@ -160,17 +160,17 @@ public class AreaTreeParser { private Locator locator; - private ParsedStructureTree structureTree; + private StructureTreeBuilder structureTreeBuilder; - private ContentHandler structureTreeBuilder; + private ContentHandler structureTreeBuilderWrapper; - private final class StructureTreeBuilder extends DelegatingContentHandler { + private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { private Attributes pageSequenceAttributes; - private StructureTreeBuilder(Attributes pageSequenceAttributes, - ParsedStructureTree structureTree) throws SAXException { - super(structureTree.getHandlerForNextPageSequence()); + private StructureTreeBuilderWrapper(Attributes pageSequenceAttributes) + throws SAXException { + super(structureTreeBuilder.getHandlerForNextPageSequence()); this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes); } @@ -216,9 +216,10 @@ public class AreaTreeParser { makers.put("bookmarkTree", new BookmarkTreeMaker()); makers.put("bookmark", new BookmarkMaker()); makers.put("destination", new DestinationMaker()); + if (userAgent.isAccessibilityEnabled()) { - structureTree = new ParsedStructureTree(tFactory); - userAgent.setStructureTree(structureTree); + structureTreeBuilder = new StructureTreeBuilder(tFactory); + userAgent.setStructureTree(structureTreeBuilder.getStructureTree()); } } @@ -296,10 +297,10 @@ public class AreaTreeParser { boolean handled = true; if ("".equals(uri)) { if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) { - structureTreeBuilder = new StructureTreeBuilder(attributes, structureTree); + structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(attributes); } else if (localName.equals("structureTree")) { if (userAgent.isAccessibilityEnabled()) { - delegate = structureTreeBuilder; + delegate = structureTreeBuilderWrapper; } else { /* Delegate to a handler that does nothing */ delegate = new DefaultHandler(); diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 9ef65ce6f..e7bdd1b23 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -46,7 +46,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.util.QName; -import org.apache.fop.accessibility.ParsedStructureTree; +import org.apache.fop.accessibility.StructureTreeBuilder; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.ElementMappingRegistry; @@ -151,17 +151,17 @@ public class IFParser implements IFConstants { private ContentHandler navParser; - private ParsedStructureTree structureTree; + private StructureTreeBuilder structureTreeBuilder; - private ContentHandler structureTreeBuilder; + private ContentHandler structureTreeBuilderWrapper; - private final class StructureTreeBuilder extends DelegatingContentHandler { + private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { private Attributes pageSequenceAttributes; - private StructureTreeBuilder(Attributes pageSequenceAttributes, - ParsedStructureTree structureTree) throws SAXException { - super(structureTree.getHandlerForNextPageSequence()); + private StructureTreeBuilderWrapper(Attributes pageSequenceAttributes) + throws SAXException { + super(structureTreeBuilder.getHandlerForNextPageSequence()); this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes); } @@ -196,8 +196,8 @@ public class IFParser implements IFConstants { elementHandlers.put(EL_IMAGE, new ImageHandler()); if (userAgent.isAccessibilityEnabled()) { - structureTree = new ParsedStructureTree(tFactory); - userAgent.setStructureTree(structureTree); + structureTreeBuilder = new StructureTreeBuilder(tFactory); + userAgent.setStructureTree(structureTreeBuilder.getStructureTree()); } } @@ -227,10 +227,10 @@ public class IFParser implements IFConstants { boolean handled = true; if (NAMESPACE.equals(uri)) { if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) { - structureTreeBuilder = new StructureTreeBuilder(attributes, structureTree); + structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(attributes); } else if (localName.equals(EL_STRUCTURE_TREE)) { if (userAgent.isAccessibilityEnabled()) { - delegate = structureTreeBuilder; + delegate = structureTreeBuilderWrapper; } else { /* Delegate to a handler that does nothing */ delegate = new DefaultHandler(); diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 9d7c15a61..b6136f036 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -63,7 +63,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler implements IFConstants, IFPainter, IFDocumentNavigationHandler { private IFDocumentHandler mimicHandler; - private int pageSequenceCounter; // used for accessibility + private int pageSequenceIndex; // used for accessibility /** Holds the intermediate format state */ private IFState state; @@ -224,7 +224,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (this.getUserAgent().isAccessibilityEnabled()) { StructureTree structureTree = getUserAgent().getStructureTree(); handler.startElement(EL_STRUCTURE_TREE); // add structure tree - NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter); + 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); diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java index b9d726bf2..3cd601bfa 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java @@ -62,7 +62,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { /** logging instance */ private static Log log = LogFactory.getLog(PDFDocumentHandler.class); - private int pageSequenceNumber; + private int pageSequenceIndex; private boolean accessEnabled; @@ -186,8 +186,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler { } if (accessEnabled) { - NodeList nodes = getUserAgent().getStructureTree().getPageSequence( - ++pageSequenceNumber); + NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++); logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage()); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 17ab1755c..380241ba0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -204,7 +204,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf private PDFLogicalStructureHandler logicalStructureHandler; - private int pageSequenceNumber; + private int pageSequenceIndex; /** Reference in the structure tree to the image being rendered. */ private String imageReference; @@ -428,8 +428,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf } pdfUtil.generateDefaultXMPMetadata(); if (accessEnabled) { - NodeList nodes = getUserAgent().getStructureTree().getPageSequence( - ++pageSequenceNumber); + NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++); logicalStructureHandler.processStructureTree(nodes, language); } } diff --git a/src/java/org/apache/fop/render/xml/XMLRenderer.java b/src/java/org/apache/fop/render/xml/XMLRenderer.java index d86814d25..a8a1a1911 100644 --- a/src/java/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/java/org/apache/fop/render/xml/XMLRenderer.java @@ -41,7 +41,6 @@ import org.xml.sax.SAXException; import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.XMLizable; -import org.apache.fop.accessibility.StructureTree; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; @@ -108,7 +107,7 @@ public class XMLRenderer extends AbstractXMLRenderer { /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */ protected Renderer mimic; - private int pageSequenceNumber; + private int pageSequenceIndex; /** * Creates a new XML renderer. @@ -446,10 +445,9 @@ public class XMLRenderer extends AbstractXMLRenderer { transferForeignObjects(pageSequence); startElement("pageSequence", atts); if (this.getUserAgent().isAccessibilityEnabled()) { - StructureTree structureTree = getUserAgent().getStructureTree(); String structureTreeElement = "structureTree"; startElement(structureTreeElement); - NodeList nodes = structureTree.getPageSequence(++pageSequenceNumber); + NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++); for (int i = 0, n = nodes.getLength(); i < n; i++) { Node node = nodes.item(i); try { -- cgit v1.2.3 From 5dd6862ad1eed75fdcc205a228aae7a46a00a46d Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 15 Oct 2009 16:25:08 +0000 Subject: Added mappings for yet unimplemented FOs. Return /NonStruct instead of null if no mapping is found for a given object, in order to at least generate a valid PDF git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@825555 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java index e3122ec39..2c13edca5 100644 --- a/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java +++ b/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java @@ -28,18 +28,24 @@ import org.apache.fop.pdf.PDFStructElem; /** * This class provides the standard mappings from Formatting Objects to PDF structure types. */ -public final class FOToPDFRoleMap { +final class FOToPDFRoleMap { private static final Map STANDARD_MAPPINGS = new java.util.HashMap(); private static final PDFName TFOOT = new PDFName("TFoot"); private static final PDFName THEAD = new PDFName("THead"); + private static final PDFName NON_STRUCT = new PDFName("NonStruct"); static { addMapping("block", "P"); - addMapping("block-container", "Div"); - PDFName st = new PDFName("Span"); + PDFName st = new PDFName("Div"); + addMapping("block-container", st); + addMapping("inline-container", st); + addMapping("table-and-caption", st); + addMapping("float", st); + + st = new PDFName("Span"); addMapping("inline", st); addMapping("wrapper", st); addMapping("character", st); @@ -58,6 +64,7 @@ public final class FOToPDFRoleMap { addMapping("external-graphic", st); addMapping("instream-foreign-object", st); + addMapping("table-caption", "Caption"); addMapping("table", "Table"); addMapping("table-body", "TBody"); addMapping("table-header", THEAD); @@ -98,8 +105,9 @@ public final class FOToPDFRoleMap { Mapper mapper = (Mapper)STANDARD_MAPPINGS.get(fo); if (mapper != null) { return mapper.getStructureType(parent); + } else { + return NON_STRUCT; } - return null; } private interface Mapper { -- cgit v1.2.3 From c7e17515ef3e7b09b5a822fe81ffbb1e21da6ff9 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 16 Oct 2009 14:12:06 +0000 Subject: Made PDFImageHandlerGraphics2D accessible git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@825902 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/pdf/PDFImageHandlerGraphics2D.java | 18 ++++++++++++++++-- src/java/org/apache/fop/render/pdf/PDFRenderer.java | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java index 18717809d..c3242827a 100644 --- a/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java @@ -35,6 +35,7 @@ import org.apache.fop.pdf.PDFXObject; import org.apache.fop.render.AbstractImageHandlerGraphics2D; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.pdf.PDFLogicalStructureHandler.MarkedContentInfo; import org.apache.fop.svg.PDFGraphics2D; /** @@ -63,6 +64,9 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D renderer.currentPage, renderer.getFontInfo()); Rectangle effPos = new Rectangle(origin.x + pos.x, origin.y + pos.y, pos.width, pos.height); + if (context.getUserAgent().isAccessibilityEnabled()) { + pdfContext.setMarkedContentInfo(renderer.addCurrentImageToStructureTree()); + } handleImage(pdfContext, image, effPos); return null; } @@ -87,7 +91,13 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D float sy = fheight / (float)imh; generator.comment("G2D start"); - generator.saveGraphicsState(); + boolean accessibilityEnabled = context.getUserAgent().isAccessibilityEnabled(); + if (accessibilityEnabled) { + MarkedContentInfo mci = pdfContext.getMarkedContentInfo(); + generator.saveGraphicsState(mci.tag, mci.mcid); + } else { + generator.saveGraphicsState(); + } generator.updateColor(Color.black, false, null); generator.updateColor(Color.black, true, null); @@ -115,7 +125,11 @@ public class PDFImageHandlerGraphics2D extends AbstractImageHandlerGraphics2D imageG2D.getGraphics2DImagePainter().paint(graphics, area); generator.add(graphics.getString()); - generator.restoreGraphicsState(); + if (accessibilityEnabled) { + generator.restoreGraphicsStateAccess(); + } else { + generator.restoreGraphicsState(); + } generator.comment("G2D end"); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 380241ba0..6188433c6 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -1347,5 +1347,9 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf public void setEncryptionParams(PDFEncryptionParams encryptionParams) { this.pdfUtil.setEncryptionParams(encryptionParams); } + + MarkedContentInfo addCurrentImageToStructureTree() { + return logicalStructureHandler.addImageContentItem(imageReference); + } } -- cgit v1.2.3 From 0a05a9f1295e06d158bba4bb7e86f96d4bd845a7 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 16 Oct 2009 15:53:13 +0000 Subject: Route message for missing alt-text property through event notification system git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@825964 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/events/EventFormatter.xml | 1 + src/java/org/apache/fop/fo/FOValidationEventProducer.java | 13 ++++++++++++- .../apache/fop/fo/extensions/ExtensionElementMapping.java | 2 +- src/java/org/apache/fop/fo/flow/AbstractGraphics.java | 6 ++++++ .../apache/fop/render/pdf/PDFLogicalStructureHandler.java | 3 --- 5 files changed, 20 insertions(+), 5 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/events/EventFormatter.xml b/src/java/org/apache/fop/events/EventFormatter.xml index 147744a0d..7561f1548 100644 --- a/src/java/org/apache/fop/events/EventFormatter.xml +++ b/src/java/org/apache/fop/events/EventFormatter.xml @@ -105,4 +105,5 @@ Any reference to it will be considered a reference to the first occurrence in th Font "{requested}" not found. Substituting with "{effective}". Unable to load font file: {fontURL}.[ Reason: {e}] Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}". + Alternate text is missing on {foElement}.{{locator}} diff --git a/src/java/org/apache/fop/fo/FOValidationEventProducer.java b/src/java/org/apache/fop/fo/FOValidationEventProducer.java index 889bf706a..ff005b1b4 100644 --- a/src/java/org/apache/fop/fo/FOValidationEventProducer.java +++ b/src/java/org/apache/fop/fo/FOValidationEventProducer.java @@ -36,7 +36,9 @@ public interface FOValidationEventProducer extends EventProducer { /** * Provider class for the event producer. */ - class Provider { + final class Provider { + + private Provider() { } /** * Returns an event producer. @@ -354,4 +356,13 @@ public interface FOValidationEventProducer extends EventProducer { void unknownFormattingObject(Object source, String elementName, QName offendingNode, Locator loc); + /** + * Alternate text is missing for a graphic element. + * + * @param source the event source + * @param foElement name of the element (external-graphic or instream-foreign-object) + * @param loc the location of the error or null + * @event.severity WARN + */ + void altTextMissing(Object source, String foElement, Locator loc); } diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index ee2b3886e..f9a556167 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -47,7 +47,7 @@ public class ExtensionElementMapping extends ElementMapping { propertyAttributes.add("internal-destination"); propertyAttributes.add("disable-column-balancing"); //These are FOP's extension properties for accessibility - propertyAttributes.add("alt"); + propertyAttributes.add("alt-text"); } /** diff --git a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java index bd4152295..eeb06c1df 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractGraphics.java +++ b/src/java/org/apache/fop/fo/flow/AbstractGraphics.java @@ -106,6 +106,12 @@ public abstract class AbstractGraphics extends FObj scaling = pList.get(PR_SCALING).getEnum(); textAlign = pList.get(PR_TEXT_ALIGN).getEnum(); width = pList.get(PR_WIDTH).getLength(); + if (getUserAgent().isAccessibilityEnabled()) { + String altText = pList.get(PR_X_ALT_TEXT).getString(); + if (altText.equals("")) { + getFOValidationEventProducer().altTextMissing(this, getLocalName(), getLocator()); + } + } } /** diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java index 2313431f0..cfa0719ea 100644 --- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java @@ -163,9 +163,6 @@ class PDFLogicalStructureHandler { if (altTextNode != null) { structElem.put("Alt", altTextNode.getNodeValue()); } else { - // TODO route that to event notification system -// log.warn("fo:" + s -// + " requires an alternative text attribute fox:alt-text for accessibility"); structElem.put("Alt", "No alternate text specified"); } } -- cgit v1.2.3 From 2a54372f5d918492115fa3e00285af19d6f67055 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 21 Oct 2009 14:57:54 +0000 Subject: Renamed some variables and methods for consistency. Improved javadocs. Code clean-up and simplification. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@828038 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/fo/extensions/InternalElementMapping.java | 22 ++------- src/java/org/apache/fop/pdf/PDFFactory.java | 1 - src/java/org/apache/fop/pdf/PDFParentTree.java | 14 ++---- src/java/org/apache/fop/pdf/PDFRoot.java | 2 +- src/java/org/apache/fop/pdf/PDFStructTreeRoot.java | 13 ++++-- .../fop/render/AbstractRendererConfigurator.java | 10 ++-- .../fop/render/intermediate/IFConstants.java | 4 +- .../apache/fop/render/intermediate/IFParser.java | 6 +-- .../apache/fop/render/intermediate/IFRenderer.java | 2 +- .../fop/render/intermediate/IFSerializer.java | 24 +++++----- .../intermediate/extensions/AbstractAction.java | 24 +++++----- .../extensions/DocumentNavigationHandler.java | 12 ++--- .../apache/fop/render/pdf/PDFContentGenerator.java | 53 ++++++++++++---------- .../render/pdf/PDFDocumentNavigationHandler.java | 8 +--- .../fop/render/pdf/PDFLogicalStructureHandler.java | 22 ++++----- src/java/org/apache/fop/render/pdf/PDFPainter.java | 2 +- .../org/apache/fop/render/pdf/PDFRenderer.java | 2 +- .../apache/fop/render/pdf/PDFRenderingUtil.java | 2 +- 18 files changed, 104 insertions(+), 119 deletions(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java index c6802b5b3..7704c8de7 100644 --- a/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/InternalElementMapping.java @@ -25,9 +25,6 @@ import java.util.Set; import org.apache.xmlgraphics.util.QName; import org.apache.fop.fo.ElementMapping; -import org.apache.fop.fo.FONode; -import org.apache.fop.fo.UnknownXMLObj; -import org.apache.fop.fo.extensions.destination.Destination; /** * Element mapping for FOP's internal extension to XSL-FO. @@ -37,11 +34,11 @@ public class InternalElementMapping extends ElementMapping { /** The FOP extension namespace URI */ public static final String URI = "http://xmlgraphics.apache.org/fop/internal"; - private static final Set propertyAttributes = new java.util.HashSet(); + private static final Set PROPERTY_ATTRIBUTES = new java.util.HashSet(); - static { + static { //These are FOP's extension properties for accessibility - propertyAttributes.add("ptr"); + PROPERTY_ATTRIBUTES.add("ptr"); } /** @@ -60,16 +57,7 @@ public class InternalElementMapping extends ElementMapping { } } - /* static class DestinationMaker extends ElementMapping.Maker { - public FONode make(FONode parent) { - return new Destination(parent); - } - } */ - - - /** - * used internally for accessibility - */ + /** {@inheritDoc} */ public String getStandardPrefix() { return "foi"; } @@ -79,7 +67,7 @@ public class InternalElementMapping extends ElementMapping { if (!URI.equals(attributeName.getNamespaceURI())) { throw new IllegalArgumentException("The namespace URIs don't match"); } - return propertyAttributes.contains(attributeName.getLocalName()); + return PROPERTY_ATTRIBUTES.contains(attributeName.getLocalName()); } } diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index a1500c509..bf3399b09 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -179,7 +179,6 @@ public class PDFFactory { * @param cropBox the CropBox area * @param bleedBox the BleedBox area * @param trimBox the TrimBox area - * @param currentPageParentKey the integer key in the structural parent tree * * @return the created /Page object */ diff --git a/src/java/org/apache/fop/pdf/PDFParentTree.java b/src/java/org/apache/fop/pdf/PDFParentTree.java index 7528aa299..7876bbc0c 100644 --- a/src/java/org/apache/fop/pdf/PDFParentTree.java +++ b/src/java/org/apache/fop/pdf/PDFParentTree.java @@ -20,20 +20,14 @@ package org.apache.fop.pdf; /** - * Class representing a PDF /ParentTree + * Class representing a PDF /ParentTree. */ public class PDFParentTree extends PDFNumberTreeNode { /** - * Create the /ParentTree NumberTreeNode - */ - public PDFParentTree() { - super(); - } - - /** - * Get the parentTree. - * @return parentTree as PDFNumsArray + * Returns the number tree corresponding to this parent tree. + * + * @return the number tree */ public PDFNumsArray getNums() { PDFNumsArray nums = super.getNums(); diff --git a/src/java/org/apache/fop/pdf/PDFRoot.java b/src/java/org/apache/fop/pdf/PDFRoot.java index 3057a9e4d..f71841005 100644 --- a/src/java/org/apache/fop/pdf/PDFRoot.java +++ b/src/java/org/apache/fop/pdf/PDFRoot.java @@ -66,7 +66,7 @@ public class PDFRoot extends PDFDictionary { */ public PDFRoot(int objnum, PDFPages pages) { super(); - setObjectNumber(objnum); + setObjectNumber(objnum); put("Type", new PDFName("Catalog")); setRootPages(pages); } diff --git a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java index 0840c7a4b..5b3f63106 100644 --- a/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java +++ b/src/java/org/apache/fop/pdf/PDFStructTreeRoot.java @@ -25,7 +25,8 @@ package org.apache.fop.pdf; public class PDFStructTreeRoot extends PDFDictionary { /** - * Create the /StructTreeRoot dictionary. + * Creates a new /StructTreeRoot dictionary. + * * @param parentTree the value of the ParenTree entry */ PDFStructTreeRoot(PDFParentTree parentTree) { @@ -35,16 +36,18 @@ public class PDFStructTreeRoot extends PDFDictionary { } /** - * Get the kids. - * @return the kids + * Returns the children element of this StructTreeRoot. + * + * @return the value of the K entry */ public PDFArray getKids() { return (PDFArray)get("K"); } /** - * Adds a kid. - * @param kid to be added + * Adds the given object to the array of kids. + * + * @param kid an object to be added to the K entry */ public void addKid(PDFObject kid) { getKids().add(kid); diff --git a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java index c1a8bc182..e1bc10440 100644 --- a/src/java/org/apache/fop/render/AbstractRendererConfigurator.java +++ b/src/java/org/apache/fop/render/AbstractRendererConfigurator.java @@ -30,7 +30,7 @@ import org.apache.fop.apps.FOUserAgent; public abstract class AbstractRendererConfigurator extends AbstractConfigurator { private static final String TYPE = "renderer"; - + /** * Default constructor * @param userAgent user agent @@ -46,7 +46,7 @@ public abstract class AbstractRendererConfigurator extends AbstractConfigurator */ protected Configuration getRendererConfig(Renderer renderer) { return super.getConfig(renderer.getMimeType()); - } + } /** * Returns the configuration subtree for a specific renderer. @@ -55,13 +55,13 @@ public abstract class AbstractRendererConfigurator extends AbstractConfigurator */ protected Configuration getRendererConfig(String mimeType) { return super.getConfig(mimeType); - } - + } + /** * {@inheritDoc} */ public String getType() { return TYPE; - } + } } diff --git a/src/java/org/apache/fop/render/intermediate/IFConstants.java b/src/java/org/apache/fop/render/intermediate/IFConstants.java index 4c9b9fc8d..fa234b4db 100644 --- a/src/java/org/apache/fop/render/intermediate/IFConstants.java +++ b/src/java/org/apache/fop/render/intermediate/IFConstants.java @@ -50,6 +50,6 @@ public interface IFConstants extends XMLConstants { String EL_BORDER_RECT = "border-rect"; String EL_FONT = "font"; String EL_TEXT = "text"; - /** used for accessibility */ - String EL_STRUCTURE_TREE = "structure-tree"; + /** Parent element of the logical structure tree. */ + String EL_STRUCTURE_TREE = "structure-tree"; } diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index e7bdd1b23..45b4816a5 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -551,7 +551,7 @@ public class IFParser implements IFConstants { s = lastAttributes.getValue("word-spacing"); int wordSpacing = (s != null ? Integer.parseInt(s) : 0); int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx"); - setAccessibilityPointer(lastAttributes); + setStructurePointer(lastAttributes); painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString()); resetStructurePointer(); } @@ -648,7 +648,7 @@ public class IFParser implements IFConstants { int height = Integer.parseInt(lastAttributes.getValue("height")); Map foreignAttributes = getForeignAttributes(lastAttributes); establishForeignAttributes(foreignAttributes); - setAccessibilityPointer(lastAttributes); + setStructurePointer(lastAttributes); if (foreignObject != null) { painter.drawImage(foreignObject, new Rectangle(x, y, width, height)); @@ -716,7 +716,7 @@ public class IFParser implements IFConstants { return foreignAttributes; } - private void setAccessibilityPointer(Attributes attributes) { + private void setStructurePointer(Attributes attributes) { String ptr = attributes.getValue("ptr"); if (ptr != null && ptr.length() > 0) { establishStructurePointer(ptr); diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index 570c7246a..13ac401a7 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -961,7 +961,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer { // warn if link trait found but not allowed, else create link if (linkTraitFound) { - action.setPtr(ptr); // used for accessibility + action.setStructurePointer(ptr); // used for accessibility Link link = new Link(action, ipRect); this.deferredLinks.add(link); } diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index b6136f036..2401b1202 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -411,10 +411,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); - String ptr = getContext().getStructurePointer(); - if (ptr != null) { - addAttribute(atts, "ptr", ptr); // used for accessibility - } + addStructurePointerAttribute(atts); handler.element(EL_IMAGE, atts); } catch (SAXException e) { throw new IFException("SAX error in startGroup()", e); @@ -441,10 +438,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler addAttribute(atts, "width", Integer.toString(rect.width)); addAttribute(atts, "height", Integer.toString(rect.height)); addForeignAttributes(atts); - String ptr = getContext().getStructurePointer(); - if (ptr != null) { - addAttribute(atts, "ptr", ptr); // used for accessibility - } + addStructurePointerAttribute(atts); handler.startElement(EL_IMAGE, atts); new DOM2SAX(handler).writeDocument(doc, true); handler.endElement(EL_IMAGE); @@ -558,10 +552,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler if (dx != null) { addAttribute(atts, "dx", IFUtil.toString(dx)); } - String ptr = getContext().getStructurePointer(); - if (ptr != null) { - addAttribute(atts, "ptr", ptr); // used for accessibility - } + addStructurePointerAttribute(atts); handler.startElement(EL_TEXT, atts); char[] chars = text.toCharArray(); handler.characters(chars, 0, chars.length); @@ -657,6 +648,13 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler XMLUtil.addAttribute(atts, localName, value); } + private void addStructurePointerAttribute(AttributesImpl atts) { + String ptr = getContext().getStructurePointer(); + if (ptr != null) { + addAttribute(atts, "ptr", ptr); + } + } + // ---=== IFDocumentNavigationHandler ===--- private Map incompleteActions = new java.util.HashMap(); @@ -729,7 +727,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler atts.addAttribute(null, "rect", "rect", XMLConstants.CDATA, IFUtil.toString(link.getTargetRect())); if (getUserAgent().isAccessibilityEnabled()) { - addAttribute(atts, "ptr", link.getAction().getPtr()); + addAttribute(atts, "ptr", link.getAction().getStructurePointer()); } try { handler.startElement(DocumentNavigationExtensionConstants.LINK, atts); diff --git a/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java b/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java index 8a4237af1..340b2e068 100644 --- a/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java +++ b/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java @@ -27,7 +27,7 @@ import org.apache.xmlgraphics.util.XMLizable; public abstract class AbstractAction implements XMLizable { private String id; - private String ptr; // used for accessibility + private String structurePointer; /** * Sets an ID to make the action referencable. @@ -44,23 +44,23 @@ public abstract class AbstractAction implements XMLizable { public String getID() { return this.id; } - + /** - * Used for accessibility - * @param s representing the ptr + * Sets the structure element corresponding to this action. + * @param structurePointer a reference to the structure element */ - public void setPtr(String s) { - this.ptr = s; + public void setStructurePointer(String structurePointer) { + this.structurePointer = structurePointer; } - + /** - * Used for accessibility - * @return the ptr + * Returns the structure element corresponding to this action. + * @return the reference to the structure element */ - public String getPtr() { - return this.ptr; + public String getStructurePointer() { + return structurePointer; } - + /** * Indicates whether the action has an ID and is therefore referencable. * @return true if the action has an ID diff --git a/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java b/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java index 6a27a929d..5ca480f4a 100644 --- a/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java @@ -48,7 +48,7 @@ public class DocumentNavigationHandler extends DefaultHandler private IFDocumentNavigationHandler navHandler; - private String accessibilityPointer; + private String structurePointer; /** * Main constructor. @@ -98,7 +98,7 @@ public class DocumentNavigationHandler extends DefaultHandler throw new SAXException(localName + " must be the root element!"); } Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect"); - accessibilityPointer = attributes.getValue("ptr"); + structurePointer = attributes.getValue("ptr"); Link link = new Link(null, targetRect); objectStack.push(link); } else if (GOTO_XY.getLocalName().equals(localName)) { @@ -121,8 +121,8 @@ public class DocumentNavigationHandler extends DefaultHandler } action = new GoToXYAction(id, pageIndex, location); } - if (accessibilityPointer != null) { - action.setPtr(accessibilityPointer); + if (structurePointer != null) { + action.setStructurePointer(structurePointer); } objectStack.push(action); } else if (GOTO_URI.getLocalName().equals(localName)) { @@ -134,8 +134,8 @@ public class DocumentNavigationHandler extends DefaultHandler if (id != null) { action.setID(id); } - if (accessibilityPointer != null) { - action.setPtr(accessibilityPointer); + if (structurePointer != null) { + action.setStructurePointer(structurePointer); } objectStack.push(action); } else { diff --git a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java index d827c1b46..fb5fc4e8d 100644 --- a/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java +++ b/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java @@ -168,13 +168,13 @@ public class PDFContentGenerator { * the sequenceNum is ignored and instead of a BDC with the MCID as parameter, an "Artifact" * and a BMC command is generated. * @param structElemType Structure Element Type - * @param sequenceNum Sequence number + * @param mcid Sequence number */ - protected void beginMarkedContentSequence(String structElemType, int sequenceNum) { + protected void beginMarkedContentSequence(String structElemType, int mcid) { assert !this.inMarkedContentSequence; assert !this.inArtifactMode; if (structElemType != null) { - currentStream.add(structElemType + " <>\n" + currentStream.add(structElemType + " <>\n" + "BDC\n"); } else { currentStream.add("/Artifact\nBMC\n"); @@ -202,12 +202,18 @@ public class PDFContentGenerator { } } - /** {@inheritDoc} */ + /** + * Same as {@link #restoreGraphicsState(boolean)}, with true as + * a parameter. + */ protected void restoreGraphicsState() { restoreGraphicsState(true); } - /** used for accessibility */ + /** + * Same as {@link #restoreGraphicsState()}, additionally ending the current + * marked content sequence if any. + */ protected void restoreGraphicsStateAccess() { endTextObject(); currentStream.add("Q\n"); @@ -218,9 +224,12 @@ public class PDFContentGenerator { } /** - * used for accessibility, separates 2 text elements - * @param structElemType of parent of new text element - * @param mcid of new text element + * Separates 2 text elements, ending the current marked content sequence and + * starting a new one. + * + * @param structElemType structure element type + * @param mcid sequence number + * @see #beginMarkedContentSequence(String, int) */ protected void separateTextElements(String structElemType, int mcid) { textutil.endTextObject(); @@ -237,24 +246,20 @@ public class PDFContentGenerator { } /** - * Accessibility beginTextObject - * @param structElemType of parent - * @param mcid of text element + * Indicates the beginning of a marked-content text object. + * + * @param structElemType structure element type + * @param mcid sequence number + * @see #beginTextObject() + * @see #beginMarkedContentSequence(String, int) */ - protected void beginTextObjectAccess(String structElemType, int mcid) { + protected void beginTextObject(String structElemType, int mcid) { if (!textutil.isInTextObject()) { beginMarkedContentSequence(structElemType, mcid); textutil.beginTextObject(); } } - /** - * Accessibility begin of LeaderTextObject - */ - public void beginLeaderTextObject() { - beginTextObjectAccess(null, 0); - } - /** Indicates the end of a text object. */ protected void endTextObject() { if (textutil.isInTextObject()) { @@ -407,15 +412,17 @@ public class PDFContentGenerator { } /** - * Places a previously registered image at a certain place on the page. - * Accessibility version + * Places a previously registered image at a certain place on the page, + * bracketing it as a marked-content sequence. + * * @param x X coordinate * @param y Y coordinate * @param w width for image * @param h height for image * @param xobj the image XObject - * @param structElemType of this image - * @param mcid of this image + * @param structElemType structure element type + * @param mcid sequence number + * @see #beginMarkedContentSequence(String, int) */ public void placeImage(float x, float y, float w, float h, PDFXObject xobj, String structElemType, int mcid) { diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index 2407e0dd2..b86bf7e3d 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -25,9 +25,6 @@ import java.awt.geom.Rectangle2D; import java.util.Iterator; import java.util.Map; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.apache.fop.pdf.PDFAction; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFactory; @@ -49,7 +46,7 @@ import org.apache.fop.render.pdf.PDFDocumentHandler.PageReference; * Implementation of the {@link IFDocumentNavigationHandler} interface for PDF output. */ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler { - private static Log log = LogFactory.getLog(PDFDocumentHandler.class); + private final PDFDocumentHandler documentHandler; private final Map incompleteActions = new java.util.HashMap(); @@ -114,8 +111,7 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler PDFLink pdfLink = getPDFDoc().getFactory().makeLink( targetRect2D, pdfAction); if (pdfLink != null) { - //accessibility: ptr has a value - String ptr = link.getAction().getPtr(); + String ptr = link.getAction().getStructurePointer(); if (ptr != null && ptr.length() > 0) { documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr); } diff --git a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java index cfa0719ea..d55094d48 100644 --- a/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java @@ -204,8 +204,8 @@ class PDFLogicalStructureHandler { parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray); } - private MarkedContentInfo addToParentTree(String reference) { - PDFStructElem parent = (PDFStructElem) structTreeMap.get(reference); + private MarkedContentInfo addToParentTree(String structurePointer) { + PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer); if (parent == null) { return ARTIFACT; } else { @@ -220,7 +220,7 @@ class PDFLogicalStructureHandler { * Adds a content item corresponding to text into the structure tree, if * there is a structure element associated to it. * - * @param parentReference reference to the parent structure element of the + * @param structurePointer reference to the parent structure element of the * piece of text * @return the necessary information for bracketing the content as a * marked-content sequence. If there is no element in the structure tree @@ -228,8 +228,8 @@ class PDFLogicalStructureHandler { * {@link MarkedContentInfo#tag} value is null. The content * must then be treated as an artifact. */ - MarkedContentInfo addTextContentItem(String parentReference) { - MarkedContentInfo mci = addToParentTree(parentReference); + MarkedContentInfo addTextContentItem(String structurePointer) { + MarkedContentInfo mci = addToParentTree(structurePointer); if (mci != ARTIFACT) { PDFDictionary contentItem = new PDFDictionary(); contentItem.put("Type", MCR); @@ -244,7 +244,7 @@ class PDFLogicalStructureHandler { * Adds a content item corresponding to an image into the structure tree, if * there is a structure element associated to it. * - * @param parentReference reference to the parent structure element of the + * @param structurePointer reference to the parent structure element of the * image * @return the necessary information for bracketing the content as a * marked-content sequence. If there is no element in the structure tree @@ -252,8 +252,8 @@ class PDFLogicalStructureHandler { * {@link MarkedContentInfo#tag} value is null. The image * must then be treated as an artifact. */ - MarkedContentInfo addImageContentItem(String parentReference) { - MarkedContentInfo mci = addToParentTree(parentReference); + MarkedContentInfo addImageContentItem(String structurePointer) { + MarkedContentInfo mci = addToParentTree(structurePointer); if (mci != ARTIFACT) { mci.parent.setMCIDKid(mci.mcid); mci.parent.setPage(this.currentPage); @@ -282,9 +282,9 @@ class PDFLogicalStructureHandler { * tree. * * @param link a link - * @param reference reference to the corresponding parent structure element + * @param structurePointer reference to the corresponding parent structure element */ - void addLinkContentItem(PDFLink link, String reference) { + void addLinkContentItem(PDFLink link, String structurePointer) { int structParent = getNextParentTreeKey(); link.setStructParent(structParent); parentTree.getNums().put(structParent, link); @@ -292,7 +292,7 @@ class PDFLogicalStructureHandler { contentItem.put("Type", OBJR); contentItem.put("Pg", this.currentPage); contentItem.put("Obj", link); - PDFStructElem parent = (PDFStructElem) structTreeMap.get(reference); + PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer); parent.addKid(contentItem); } diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 2ae28b6db..f72f09ad0 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -302,7 +302,7 @@ public class PDFPainter extends AbstractIFPainter { generator.separateTextElements(mci.tag, mci.mcid); } generator.updateColor(state.getTextColor(), true, null); - generator.beginTextObjectAccess(mci.tag, mci.mcid); + generator.beginTextObject(mci.tag, mci.mcid); } else { generator.updateColor(state.getTextColor(), true, null); generator.beginTextObject(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 6188433c6..9fe08c2e4 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -973,7 +973,7 @@ public class PDFRenderer extends AbstractPathOrientedRenderer implements PDFConf if (generator.getTextUtil().isInTextObject()) { generator.separateTextElements(mci.tag, mci.mcid); } - generator.beginTextObjectAccess(mci.tag, mci.mcid); + generator.beginTextObject(mci.tag, mci.mcid); } else { beginTextObject(); } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 022b7111e..52d97fa31 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -110,7 +110,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants { private void initialize() { PDFEncryptionParams params - = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); + = (PDFEncryptionParams)userAgent.getRendererOptions().get(ENCRYPTION_PARAMS); if (params != null) { this.encryptionParams = params; //overwrite if available } -- cgit v1.2.3 From ac5f083758e5f884c854cc886404aac823545e1b Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 21 Oct 2009 15:02:24 +0000 Subject: Simplified the handling of the accessibility option and made it consistent with other options git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@828039 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/trunk/accessibility.xml | 2 +- src/java/org/apache/fop/apps/FOUserAgent.java | 17 +++++++++++++---- src/java/org/apache/fop/apps/FopFactory.java | 12 +++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) (limited to 'src/java') diff --git a/src/documentation/content/xdocs/trunk/accessibility.xml b/src/documentation/content/xdocs/trunk/accessibility.xml index d9fbbff1f..e7e49d7c0 100644 --- a/src/documentation/content/xdocs/trunk/accessibility.xml +++ b/src/documentation/content/xdocs/trunk/accessibility.xml @@ -47,7 +47,7 @@ fop -a -fo mydocument.fo -pdf mydocument.pdf
  • - Embedding: userAgent.getRendererOptions().put("accessibility", Boolean.TRUE); + Embedding: userAgent.setAccessibility(true);
  • Optional setting in fop.xconf file: diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 0ed5151e0..11de99e33 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -156,9 +156,7 @@ public class FOUserAgent { this.factory = factory; setBaseURL(factory.getBaseURL()); setTargetResolution(factory.getTargetResolution()); - if (this.getRendererOptions().get(AccessibilityUtil.ACCESSIBILITY) == null) { - this.rendererOptions.put(AccessibilityUtil.ACCESSIBILITY, Boolean.FALSE); - } + setAccessibility(factory.isAccessibilityEnabled()); } /** @return the associated FopFactory instance */ @@ -360,7 +358,7 @@ public class FOUserAgent { getFactory().getFontManager().setFontBaseURL(fontBaseUrl); } catch (MalformedURLException e) { throw new IllegalArgumentException(e.getMessage()); - } + } } /** @@ -650,6 +648,17 @@ public class FOUserAgent { this.conserveMemoryPolicy = conserveMemoryPolicy; } + /** + * Activates accessibility (for output formats that support it). + * + * @param accessibility true to enable accessibility support + */ + public void setAccessibility(boolean accessibility) { + if (accessibility) { + getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); + } + } + /** * Check if accessibility is enabled. * @return true if accessibility is enabled diff --git a/src/java/org/apache/fop/apps/FopFactory.java b/src/java/org/apache/fop/apps/FopFactory.java index 6693f33c4..907895c99 100644 --- a/src/java/org/apache/fop/apps/FopFactory.java +++ b/src/java/org/apache/fop/apps/FopFactory.java @@ -41,7 +41,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.image.loader.ImageContext; import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.fop.accessibility.AccessibilityUtil; import org.apache.fop.fo.ElementMapping; import org.apache.fop.fo.ElementMappingRegistry; import org.apache.fop.fonts.FontCache; @@ -187,19 +186,22 @@ public class FopFactory implements ImageContext { */ public FOUserAgent newFOUserAgent() { FOUserAgent userAgent = new FOUserAgent(this); - userAgent.getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, - Boolean.valueOf(this.accessibility)); return userAgent; } /** - * Used for accessibility to pass value to newFOUserAgent - * @param value set through xconf file + * Sets accessibility support. + * + * @param value true to enable accessibility, false otherwise */ void setAccessibility(boolean value) { this.accessibility = value; } + boolean isAccessibilityEnabled() { + return accessibility; + } + /** * Returns a new {@link Fop} instance. FOP will be configured with a default user agent * instance. -- cgit v1.2.3 From 7859b3ed2d10c712c35644164d7703192e3985d8 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Wed, 21 Oct 2009 16:31:59 +0000 Subject: Renamed TransformerNode into TransformerDefaultHandler and moved it into the a.o.f.util package. Renamed TransformerNodeEndProcessing into AccessibilityPreprocessor. Renamed AccessibilityUtil into Accessibility and simplified the code. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@828090 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/accessibility/Accessibility.java | 87 +++++++++ .../accessibility/AccessibilityPreprocessor.java | 95 +++++++++ .../fop/accessibility/AccessibilityUtil.java | 100 ---------- .../apache/fop/accessibility/TransformerNode.java | 216 --------------------- .../TransformerNodeEndProcessing.java | 103 ---------- src/java/org/apache/fop/apps/FOUserAgent.java | 6 +- src/java/org/apache/fop/apps/Fop.java | 4 +- .../org/apache/fop/cli/CommandLineOptions.java | 4 +- .../apache/fop/render/pdf/PDFRenderingUtil.java | 4 +- .../apache/fop/util/TransformerDefaultHandler.java | 160 +++++++++++++++ 10 files changed, 351 insertions(+), 428 deletions(-) create mode 100644 src/java/org/apache/fop/accessibility/Accessibility.java create mode 100644 src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.java delete mode 100644 src/java/org/apache/fop/accessibility/AccessibilityUtil.java delete mode 100644 src/java/org/apache/fop/accessibility/TransformerNode.java delete mode 100644 src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java create mode 100644 src/java/org/apache/fop/util/TransformerDefaultHandler.java (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/Accessibility.java b/src/java/org/apache/fop/accessibility/Accessibility.java new file mode 100644 index 000000000..d550b433a --- /dev/null +++ b/src/java/org/apache/fop/accessibility/Accessibility.java @@ -0,0 +1,87 @@ +/* + * 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.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.FOUserAgent; + +/** + * Helper class for FOP's accessibility features. + */ +public final class Accessibility { + + /** Constant string for the rendering options key to enable accessibility features. */ + public static final String ACCESSIBILITY = "accessibility"; + + // TODO what if the default factory is not a SAXTransformerFactory? + private static SAXTransformerFactory tfactory + = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); + + private static Templates addPtrTemplates; + + private static Templates reduceFOTreeTemplates; + + private Accessibility() { } + + /** + * Decorates the given handler so the structure tree used for accessibility + * features can be branched off the main content stream. + * @param handler the handler to decorate + * @param userAgent the user agent + * @return the decorated handler + * @throws FOPException if an error occurs setting up the decoration + */ + public static DefaultHandler decorateDefaultHandler(DefaultHandler handler, + FOUserAgent userAgent) throws FOPException { + try { + setupTemplates(); + TransformerHandler addPtr = tfactory.newTransformerHandler(addPtrTemplates); + Transformer reduceFOTree = reduceFOTreeTemplates.newTransformer(); + return new AccessibilityPreprocessor(addPtr, reduceFOTree, userAgent, handler); + } catch (TransformerConfigurationException e) { + throw new FOPException(e); + } + } + + private static synchronized void setupTemplates() throws TransformerConfigurationException { + if (addPtrTemplates == null) { + addPtrTemplates = loadTemplates("addPtr.xsl"); + } + if (reduceFOTreeTemplates == null) { + reduceFOTreeTemplates = loadTemplates("reduceFOTree.xsl"); + } + } + + private static Templates loadTemplates(String source) throws TransformerConfigurationException { + Source src = new StreamSource(Accessibility.class.getResource(source).toExternalForm()); + return tfactory.newTemplates(src); + } + +} diff --git a/src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.java b/src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.java new file mode 100644 index 000000000..1958b74a8 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/AccessibilityPreprocessor.java @@ -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.io.ByteArrayInputStream; +import java.io.InputStream; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.TransformerHandler; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import org.apache.commons.io.output.ByteArrayOutputStream; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.util.TransformerDefaultHandler; + +/** + * This class prepares an XSL-FO document for accessibility. It adds a unique + * identifier to every applicable FO, then creates the structure tree, before + * handing the document over to the regular handler. + */ +class AccessibilityPreprocessor extends TransformerDefaultHandler { + + private final ByteArrayOutputStream enrichedFOBuffer = new ByteArrayOutputStream(); + + private final Transformer reduceFOTree; + + private final FOUserAgent userAgent; + + private final DefaultHandler fopHandler; + + public AccessibilityPreprocessor(TransformerHandler addPtr, Transformer reduceFOTree, + FOUserAgent userAgent, DefaultHandler fopHandler) { + super(addPtr); + this.reduceFOTree = reduceFOTree; + this.userAgent = userAgent; + this.fopHandler = fopHandler; + getTransformerHandler().setResult(new StreamResult(enrichedFOBuffer)); + } + + /** {@inheritDoc} */ + public void endDocument() throws SAXException { + super.endDocument(); + // do the second transform to struct + try { + //TODO this must be optimized, no buffering (ex. SAX-based tee-proxy) + byte[] enrichedFO = enrichedFOBuffer.toByteArray(); + Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); + DOMResult res = new DOMResult(); + reduceFOTree.transform(src, res); + StructureTree structureTree = new StructureTree(); + NodeList pageSequences = res.getNode().getFirstChild().getChildNodes(); + for (int i = 0; i < pageSequences.getLength(); i++) { + structureTree.addPageSequenceStructure(pageSequences.item(i).getChildNodes()); + } + userAgent.setStructureTree(structureTree); + + SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setNamespaceAware(true); + saxParserFactory.setValidating(false); + SAXParser saxParser = saxParserFactory.newSAXParser(); + InputStream in = new ByteArrayInputStream(enrichedFO); + saxParser.parse(in, fopHandler); + } catch (Exception e) { + throw new SAXException(e); + } + } + +} diff --git a/src/java/org/apache/fop/accessibility/AccessibilityUtil.java b/src/java/org/apache/fop/accessibility/AccessibilityUtil.java deleted file mode 100644 index 4063d3f9f..000000000 --- a/src/java/org/apache/fop/accessibility/AccessibilityUtil.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * 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.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.stream.StreamSource; - -import org.xml.sax.helpers.DefaultHandler; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.FOUserAgent; - -/** - * Utility class for FOP's accessibility features. It provides the stylesheets used for processing - * the incoming XSL-FO stream and for setting up the transformation. - */ -public class AccessibilityUtil { - - /** Constant string for the rendering options key to enable accessibility features. */ - public static final String ACCESSIBILITY = "accessibility"; - - private static SAXTransformerFactory tfactory - = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); - - private static Templates addPtrTemplates; - private static Templates reduceFOTemplates; - - /** - * Decorates the given {@link DefaultHandler} so the structure tree used for accessibility - * features can be branched off the main content stream. - * @param handler the handler to decorate - * @param userAgent the user agent - * @return the decorated handler - * @throws FOPException if an error occurs setting up the decoration - */ - public static DefaultHandler decorateDefaultHandler(DefaultHandler handler, - FOUserAgent userAgent) throws FOPException { - DefaultHandler transformNode = new TransformerNodeEndProcessing( - getAddPtrTemplates(), handler, userAgent); - return transformNode; - } - - /** - * Returns the addPtr.xsl stylesheet. - * @return the addPtr.xsl stylesheet - * @throws FOPException if transform fails - */ - public static synchronized Templates getAddPtrTemplates() throws FOPException { - if (addPtrTemplates == null) { - //Load and cache stylesheet - Source src = new StreamSource( - AccessibilityUtil.class.getResource("addPtr.xsl").toExternalForm()); - try { - addPtrTemplates = tfactory.newTemplates(src); - } catch (TransformerConfigurationException e) { - throw new FOPException(e); - } - } - return addPtrTemplates; - } - - /** - * Returns the reduceFOTree.xsl stylesheet - * @return the reduceFOTree.xsl stylesheet - * @throws FOPException if an error occurs loading the stylesheet - */ - public static synchronized Templates getReduceFOTreeTemplates() throws FOPException { - if (reduceFOTemplates == null) { - //Load and cache stylesheet - Source src = new StreamSource( - AccessibilityUtil.class.getResource("reduceFOTree.xsl").toExternalForm()); - try { - reduceFOTemplates = tfactory.newTemplates(src); - } catch (TransformerConfigurationException e) { - throw new FOPException(e); - } - } - return reduceFOTemplates; - } - } \ No newline at end of file diff --git a/src/java/org/apache/fop/accessibility/TransformerNode.java b/src/java/org/apache/fop/accessibility/TransformerNode.java deleted file mode 100644 index b127a74b5..000000000 --- a/src/java/org/apache/fop/accessibility/TransformerNode.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * 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.Result; -import javax.xml.transform.Templates; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.sax.TransformerHandler; - -import org.xml.sax.Attributes; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.AttributesImpl; -import org.xml.sax.helpers.DefaultHandler; - -import org.apache.fop.apps.FOPException; - -/** - * Used for accessibility to run required xslt transforms - */ -class TransformerNode extends DefaultHandler { - - private TransformerHandler transformerHandler; - - /** - * This is part of a two phase construction. Call this, then call - * initResult. - * - * @param xsltTemplates - * for transform - * @throws FOPException - * for general errors - */ - public TransformerNode(Templates xsltTemplates) throws FOPException { - try { - TransformerFactory transFact = TransformerFactory.newInstance(); - SAXTransformerFactory saxTFactory = ((SAXTransformerFactory)transFact); - transformerHandler = saxTFactory.newTransformerHandler(xsltTemplates); - } catch (TransformerConfigurationException t) { - throw new FOPException(t); - } - } - - /** - * Call this after calling constructor for xsltFile only above. - * - * @param result - * of transform - */ - public void initResult(Result result) { - transformerHandler.setResult(result); - } - - /******************** start of ContentHandler ***************************/ - /** {@inheritDoc} */ - public void setDocumentLocator(Locator locator) { - transformerHandler.setDocumentLocator(locator); - } - - /** {@inheritDoc} */ - public void startDocument() throws SAXException { - transformerHandler.startDocument(); - } - - /** {@inheritDoc} */ - public void endDocument() throws SAXException { - transformerHandler.endDocument(); - } - - /** {@inheritDoc} */ - public void processingInstruction(String target, String data) throws SAXException { - transformerHandler.processingInstruction(target, data); - } - - /** {@inheritDoc} */ - public void startElement(String uri, String local, String raw, Attributes attrs) - throws SAXException { - AttributesImpl ai = new AttributesImpl(attrs); - transformerHandler.startElement(uri, local, raw, ai); - } - - /** {@inheritDoc} */ - public void characters(char[] ch, int start, int length) throws SAXException { - transformerHandler.characters(ch, start, length); - } - - /** {@inheritDoc} */ - public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { - transformerHandler.ignorableWhitespace(ch, start, length); - } - - /** {@inheritDoc} */ - public void endElement(String uri, String local, String raw) throws SAXException { - transformerHandler.endElement(uri, local, raw); - } - - /** {@inheritDoc} */ - public void skippedEntity(String string) throws SAXException { - transformerHandler.skippedEntity(string); - } - - /** {@inheritDoc} */ - public void startPrefixMapping(String string, String string1) throws SAXException { - transformerHandler.startPrefixMapping(string, string1); - } - - /** {@inheritDoc} */ - public void endPrefixMapping(String string) throws SAXException { - transformerHandler.endPrefixMapping(string); - } - - /***************************** LexicalHandlerImpl **************************/ - /** - * @param name - * - param1 - * @param pid - * - param2 - * @param lid - * - param3 - * @throws SAXException - * - if parser fails - */ - public void startDTD(String name, String pid, String lid) throws SAXException { - transformerHandler.startDTD(name, pid, lid); - } - - /** - * End of DTD - * - * @throws SAXException - * - if parser fails - */ - public void endDTD() throws SAXException { - transformerHandler.endDTD(); - } - - /** - * startEnitity. - * - * @param string - * - param 1 - * @throws SAXException - * - if parser fails - */ - public void startEntity(String string) throws SAXException { - transformerHandler.startEntity(string); - } - - /** - * end Entity - * - * @param string - * - param 1 - * @throws SAXException - * - if paser fails - */ - public void endEntity(String string) throws SAXException { - transformerHandler.endEntity(string); - } - - /** - * Start of CDATA section - * - * @throws SAXException - * - parser fails - */ - public void startCDATA() throws SAXException { - transformerHandler.startCDATA(); - } - - /** - * endCDATA section - * - * @throws SAXException - * - if paser fails - */ - public void endCDATA() throws SAXException { - transformerHandler.endCDATA(); - } - - /** - * - * @param charArray - * - the characters - * @param int1 - * - param 2 - * @param int2 - * - param 3 - * @throws SAXException - * - if paser fails - */ - public void comment(char[] charArray, int int1, int int2) throws SAXException { - transformerHandler.comment(charArray, int1, int2); - } - - /******************** End of Lexical Handler ***********************/ -} diff --git a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java b/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java deleted file mode 100644 index 36f36fdef..000000000 --- a/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.ByteArrayInputStream; -import java.io.InputStream; - -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Templates; -import javax.xml.transform.Transformer; -import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import org.apache.commons.io.output.ByteArrayOutputStream; - -import org.apache.fop.apps.FOPException; -import org.apache.fop.apps.FOUserAgent; - -/** - * An extension of TransformerNode used to run 2nd transform after completion of first - */ -class TransformerNodeEndProcessing extends TransformerNode { - - private final ByteArrayOutputStream enrichedFOBuffer = new ByteArrayOutputStream(); - private DefaultHandler delegateHandler = null; - private final FOUserAgent userAgent; - - /** - * Do a transform, but perform special processing at the end for the access - * stuff. - * - * @param xsltTemplates Transform to do. - * @param fopHandler Used in the end processing - * @param userAgent the userAgent - * @throws FOPException - * if transform fails - */ - public TransformerNodeEndProcessing(Templates xsltTemplates, DefaultHandler fopHandler, - FOUserAgent userAgent) throws FOPException { - super(xsltTemplates); - delegateHandler = fopHandler; - this.userAgent = userAgent; - Result res1 = new StreamResult(enrichedFOBuffer); - super.initResult(res1); - } - - /** {@inheritDoc} */ - public void endDocument() throws SAXException { - super.endDocument(); - // do the second transform to struct - try { - //TODO this must be optimized, no buffering (ex. SAX-based tee-proxy) - byte[] enrichedFO = enrichedFOBuffer.toByteArray(); - Transformer transformer = AccessibilityUtil.getReduceFOTreeTemplates().newTransformer(); - Source src = new StreamSource(new ByteArrayInputStream(enrichedFO)); - DOMResult res = new DOMResult(); - transformer.transform(src, res); - StructureTree structureTree = new StructureTree(); - NodeList pageSequences = res.getNode().getFirstChild().getChildNodes(); - for (int i = 0; i < pageSequences.getLength(); i++) { - structureTree.addPageSequenceStructure(pageSequences.item(i).getChildNodes()); - } - userAgent.setStructureTree(structureTree); - - SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setNamespaceAware(true); - saxParserFactory.setValidating(false); - SAXParser saxParser = saxParserFactory.newSAXParser(); - InputStream in = new ByteArrayInputStream(enrichedFO); - saxParser.parse(in, delegateHandler); - } catch (Exception e) { - // TODO Auto-generated catch block - throw new SAXException(e); - } - - } - -} diff --git a/src/java/org/apache/fop/apps/FOUserAgent.java b/src/java/org/apache/fop/apps/FOUserAgent.java index 11de99e33..0a65203cc 100644 --- a/src/java/org/apache/fop/apps/FOUserAgent.java +++ b/src/java/org/apache/fop/apps/FOUserAgent.java @@ -37,7 +37,7 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext; import org.apache.fop.Version; -import org.apache.fop.accessibility.AccessibilityUtil; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.accessibility.StructureTree; import org.apache.fop.events.DefaultEventBroadcaster; import org.apache.fop.events.Event; @@ -655,7 +655,7 @@ public class FOUserAgent { */ public void setAccessibility(boolean accessibility) { if (accessibility) { - getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); + getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE); } } @@ -664,7 +664,7 @@ public class FOUserAgent { * @return true if accessibility is enabled */ public boolean isAccessibilityEnabled() { - Boolean enabled = (Boolean)this.getRendererOptions().get(AccessibilityUtil.ACCESSIBILITY); + Boolean enabled = (Boolean)this.getRendererOptions().get(Accessibility.ACCESSIBILITY); if (enabled != null) { return enabled.booleanValue(); } else { diff --git a/src/java/org/apache/fop/apps/Fop.java b/src/java/org/apache/fop/apps/Fop.java index 9dfa70325..07fd4c0a4 100644 --- a/src/java/org/apache/fop/apps/Fop.java +++ b/src/java/org/apache/fop/apps/Fop.java @@ -24,7 +24,7 @@ import java.io.OutputStream; import org.xml.sax.helpers.DefaultHandler; -import org.apache.fop.accessibility.AccessibilityUtil; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.fo.FOTreeBuilder; /** @@ -112,7 +112,7 @@ public class Fop { createDefaultHandler(); } if (this.foUserAgent.isAccessibilityEnabled()) { - return AccessibilityUtil.decorateDefaultHandler(this.foTreeBuilder, foUserAgent); + return Accessibility.decorateDefaultHandler(this.foTreeBuilder, foUserAgent); } else { return this.foTreeBuilder; } diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java index e0dc0a057..043dfe3c8 100644 --- a/src/java/org/apache/fop/cli/CommandLineOptions.java +++ b/src/java/org/apache/fop/cli/CommandLineOptions.java @@ -36,7 +36,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fop.Version; -import org.apache.fop.accessibility.AccessibilityUtil; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.FopFactory; @@ -342,7 +342,7 @@ public class CommandLineOptions { } else if (args[i].equals("-if")) { i = i + parseIntermediateFormatOption(args, i); } else if (args[i].equals("-a")) { - this.renderingOptions.put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); + this.renderingOptions.put(Accessibility.ACCESSIBILITY, Boolean.TRUE); } else if (args[i].equals("-v")) { /* Currently just print the version */ printVersion(); diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java index 52d97fa31..3d68812b1 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java @@ -37,7 +37,7 @@ import org.apache.xmlgraphics.xmp.Metadata; import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter; import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema; -import org.apache.fop.accessibility.AccessibilityUtil; +import org.apache.fop.accessibility.Accessibility; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.pdf.PDFAMode; @@ -164,7 +164,7 @@ class PDFRenderingUtil implements PDFConfigurationConstants { } if (this.pdfAMode.isPDFA1LevelA()) { //Enable accessibility if PDF/A-1a is enabled because it requires tagged PDF. - userAgent.getRendererOptions().put(AccessibilityUtil.ACCESSIBILITY, Boolean.TRUE); + userAgent.getRendererOptions().put(Accessibility.ACCESSIBILITY, Boolean.TRUE); } s = (String)userAgent.getRendererOptions().get(PDF_X_MODE); if (s != null) { diff --git a/src/java/org/apache/fop/util/TransformerDefaultHandler.java b/src/java/org/apache/fop/util/TransformerDefaultHandler.java new file mode 100644 index 000000000..cf07cc836 --- /dev/null +++ b/src/java/org/apache/fop/util/TransformerDefaultHandler.java @@ -0,0 +1,160 @@ +/* + * 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 javax.xml.transform.sax.TransformerHandler; + +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.ext.DefaultHandler2; +import org.xml.sax.helpers.AttributesImpl; + +/** + * A DefaultHandler implementation that delegates all the method calls to a + * {@link TransformerHandler} instance. + */ +public class TransformerDefaultHandler extends DefaultHandler2 { + + private TransformerHandler transformerHandler; + + /** + * Creates a new instance delegating to the given TransformerHandler object. + * + * @param transformerHandler the object to which all the method calls will + * be delegated + */ + public TransformerDefaultHandler(TransformerHandler transformerHandler) { + this.transformerHandler = transformerHandler; + } + + /** + * Returns the delegate TransformerHandler instance. + * + * @return the object to which all method calls are delegated + */ + public TransformerHandler getTransformerHandler() { + return transformerHandler; + } + + /** {@inheritDoc} */ + public void setDocumentLocator(Locator locator) { + transformerHandler.setDocumentLocator(locator); + } + + /** {@inheritDoc} */ + public void startDocument() throws SAXException { + transformerHandler.startDocument(); + } + + /** {@inheritDoc} */ + public void endDocument() throws SAXException { + transformerHandler.endDocument(); + } + + /** {@inheritDoc} */ + public void startPrefixMapping(String prefix, String uri) throws SAXException { + transformerHandler.startPrefixMapping(prefix, uri); + } + + /** {@inheritDoc} */ + public void endPrefixMapping(String string) throws SAXException { + transformerHandler.endPrefixMapping(string); + } + + /** {@inheritDoc} */ + public void startElement(String uri, String localName, String qName, Attributes attrs) + throws SAXException { + AttributesImpl ai = new AttributesImpl(attrs); + transformerHandler.startElement(uri, localName, qName, ai); + } + + /** {@inheritDoc} */ + public void endElement(String uri, String localName, String qName) throws SAXException { + transformerHandler.endElement(uri, localName, qName); + } + + /** {@inheritDoc} */ + public void characters(char[] ch, int start, int length) throws SAXException { + transformerHandler.characters(ch, start, length); + } + + /** {@inheritDoc} */ + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + transformerHandler.ignorableWhitespace(ch, start, length); + } + + /** {@inheritDoc} */ + public void processingInstruction(String target, String data) throws SAXException { + transformerHandler.processingInstruction(target, data); + } + + /** {@inheritDoc} */ + public void skippedEntity(String name) throws SAXException { + transformerHandler.skippedEntity(name); + } + + /** {@inheritDoc} */ + public void notationDecl(String name, String publicId, String systemId) throws SAXException { + transformerHandler.notationDecl(name, publicId, systemId); + } + + /** {@inheritDoc} */ + public void unparsedEntityDecl(String name, String publicId, String systemId, + String notationName) throws SAXException { + transformerHandler.unparsedEntityDecl(name, publicId, systemId, notationName); + } + + /** {@inheritDoc} */ + public void startDTD(String name, String pid, String lid) throws SAXException { + transformerHandler.startDTD(name, pid, lid); + } + + /** {@inheritDoc} */ + public void endDTD() throws SAXException { + transformerHandler.endDTD(); + } + + /** {@inheritDoc} */ + public void startEntity(String name) throws SAXException { + transformerHandler.startEntity(name); + } + + /** {@inheritDoc} */ + public void endEntity(String name) throws SAXException { + transformerHandler.endEntity(name); + } + + /** {@inheritDoc} */ + public void startCDATA() throws SAXException { + transformerHandler.startCDATA(); + } + + /** {@inheritDoc} */ + public void endCDATA() throws SAXException { + transformerHandler.endCDATA(); + } + + /** {@inheritDoc} */ + public void comment(char[] charArray, int start, int length) throws SAXException { + transformerHandler.comment(charArray, start, length); + } + +} -- cgit v1.2.3 From 444ea54c14025e69be8a7e098a5b5de698d3fafc Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 22 Oct 2009 15:30:13 +0000 Subject: Issue an error when attempting to render an intermediate XML file in accessibility mode, but that file wasn't generated with accessibility (i.e., does not contain the structure tree) git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@828747 13f79535-47bb-0310-9956-ffa450edef68 --- .../accessibility/AccessibilityEventProducer.java | 54 ++++++++++++++++++++++ .../accessibility/AccessibilityEventProducer.xml | 4 ++ src/java/org/apache/fop/area/AreaTreeParser.java | 24 ++++++++-- .../apache/fop/render/intermediate/IFParser.java | 24 ++++++++-- 4 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 src/java/org/apache/fop/accessibility/AccessibilityEventProducer.java create mode 100644 src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml (limited to 'src/java') diff --git a/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.java b/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.java new file mode 100644 index 000000000..9a74b7ca8 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.accessibility; + +import org.apache.fop.events.EventBroadcaster; +import org.apache.fop.events.EventProducer; + +/** + * Event producer for accessibility-related events. + */ +public interface AccessibilityEventProducer extends EventProducer { + + /** Provider class for the event producer. */ + public final class Provider { + + private Provider() { } + + /** + * Returns an event producer. + * + * @param broadcaster the event broadcaster to use + * @return the event producer + */ + public static AccessibilityEventProducer get(EventBroadcaster broadcaster) { + return (AccessibilityEventProducer) broadcaster.getEventProducerFor( + AccessibilityEventProducer.class); + } + } + + /** + * The structure tree is missing in the XML file. + * + * @param source the event source + * @event.severity FATAL + */ + void noStructureTreeInXML(Object source); +} diff --git a/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml b/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml new file mode 100644 index 000000000..70466c2e9 --- /dev/null +++ b/src/java/org/apache/fop/accessibility/AccessibilityEventProducer.xml @@ -0,0 +1,4 @@ + + + Accessibility is enabled but structure tree is missing in XML file. Please disable accessibility, or re-generate XML file in accessibility mode. + diff --git a/src/java/org/apache/fop/area/AreaTreeParser.java b/src/java/org/apache/fop/area/AreaTreeParser.java index 784ca0684..ffffda7f4 100644 --- a/src/java/org/apache/fop/area/AreaTreeParser.java +++ b/src/java/org/apache/fop/area/AreaTreeParser.java @@ -57,6 +57,7 @@ import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; import org.apache.xmlgraphics.util.QName; +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; @@ -164,19 +165,19 @@ public class AreaTreeParser { private ContentHandler structureTreeBuilderWrapper; - private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { + private Attributes pageSequenceAttributes; - private Attributes pageSequenceAttributes; + private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { - private StructureTreeBuilderWrapper(Attributes pageSequenceAttributes) + private StructureTreeBuilderWrapper() throws SAXException { super(structureTreeBuilder.getHandlerForNextPageSequence()); - this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes); } public void endDocument() throws SAXException { super.endDocument(); startAreaTreeElement("pageSequence", pageSequenceAttributes); + pageSequenceAttributes = null; } } @@ -297,7 +298,8 @@ public class AreaTreeParser { boolean handled = true; if ("".equals(uri)) { if (localName.equals("pageSequence") && userAgent.isAccessibilityEnabled()) { - structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(attributes); + structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(); + pageSequenceAttributes = new AttributesImpl(attributes); } else if (localName.equals("structureTree")) { if (userAgent.isAccessibilityEnabled()) { delegate = structureTreeBuilderWrapper; @@ -309,6 +311,18 @@ public class AreaTreeParser { 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 { diff --git a/src/java/org/apache/fop/render/intermediate/IFParser.java b/src/java/org/apache/fop/render/intermediate/IFParser.java index 45b4816a5..da5d8a623 100644 --- a/src/java/org/apache/fop/render/intermediate/IFParser.java +++ b/src/java/org/apache/fop/render/intermediate/IFParser.java @@ -46,6 +46,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.xmlgraphics.util.QName; +import org.apache.fop.accessibility.AccessibilityEventProducer; import org.apache.fop.accessibility.StructureTreeBuilder; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fo.ElementMapping; @@ -155,19 +156,19 @@ public class IFParser implements IFConstants { private ContentHandler structureTreeBuilderWrapper; - private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { + private Attributes pageSequenceAttributes; - private Attributes pageSequenceAttributes; + private final class StructureTreeBuilderWrapper extends DelegatingContentHandler { - private StructureTreeBuilderWrapper(Attributes pageSequenceAttributes) + private StructureTreeBuilderWrapper() throws SAXException { super(structureTreeBuilder.getHandlerForNextPageSequence()); - this.pageSequenceAttributes = new AttributesImpl(pageSequenceAttributes); } public void endDocument() throws SAXException { super.endDocument(); startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes); + pageSequenceAttributes = null; } } @@ -227,7 +228,8 @@ public class IFParser implements IFConstants { boolean handled = true; if (NAMESPACE.equals(uri)) { if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) { - structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(attributes); + pageSequenceAttributes = new AttributesImpl(attributes); + structureTreeBuilderWrapper = new StructureTreeBuilderWrapper(); } else if (localName.equals(EL_STRUCTURE_TREE)) { if (userAgent.isAccessibilityEnabled()) { delegate = structureTreeBuilderWrapper; @@ -239,6 +241,18 @@ public class IFParser implements IFConstants { 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 = startIFElement(localName, attributes); } } else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) { -- cgit v1.2.3 From f656784237c7d7ddd307a3b440dab55de9024b21 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Thu, 22 Oct 2009 15:40:38 +0000 Subject: Avoid NPE if intermediate XML was generated in accessibility mode but not the PDF git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@828754 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/java') diff --git a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java index b86bf7e3d..5e1b1b250 100644 --- a/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java +++ b/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java @@ -112,7 +112,8 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler targetRect2D, pdfAction); if (pdfLink != null) { String ptr = link.getAction().getStructurePointer(); - if (ptr != null && ptr.length() > 0) { + if (documentHandler.getUserAgent().isAccessibilityEnabled() + && ptr != null && ptr.length() > 0) { documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr); } documentHandler.currentPage.addAnnotation(pdfLink); -- cgit v1.2.3