You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2009/10/27 20:07:58 UTC

svn commit: r830293 [2/2] - in /xmlgraphics/fop/trunk: ./ src/documentation/content/xdocs/ src/documentation/content/xdocs/trunk/ src/java/META-INF/services/ src/java/org/apache/fop/accessibility/ src/java/org/apache/fop/apps/ src/java/org/apache/fop/a...

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFPage.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFPage.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFPage.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFPage.java Tue Oct 27 19:07:52 2009
@@ -154,4 +154,33 @@
         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);
+        //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, <code>null</code> if the entry has not been set
+     */
+    public Integer getStructParents() {
+        return (Integer) get("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);
+    }
+
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFProfile.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFProfile.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFProfile.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFProfile.java Tue Oct 27 19:07:52 2009
@@ -58,9 +58,6 @@
      */
     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 @@
         }
     }
 
+    /**
+     * 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();

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFRoot.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFRoot.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFRoot.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFRoot.java Tue Oct 27 19:07:52 2009
@@ -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 @@
      * 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 @@
         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.
      *
@@ -252,4 +261,39 @@
         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()
+    }
+
+    /**
+     * Returns the MarkInfo dictionary.
+     * @return the MarkInfo dictionary (or null if it's not present)
+     */
+    public PDFDictionary getMarkInfo() {
+        return (PDFDictionary)get("MarkInfo");
+    }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRendererConfigurator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRendererConfigurator.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRendererConfigurator.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRendererConfigurator.java Tue Oct 27 19:07:52 2009
@@ -20,6 +20,7 @@
 package org.apache.fop.render;
 
 import org.apache.avalon.framework.configuration.Configuration;
+
 import org.apache.fop.apps.FOUserAgent;
 
 /**
@@ -29,7 +30,7 @@
 public abstract class AbstractRendererConfigurator extends AbstractConfigurator {
 
     private static final String TYPE = "renderer";
-    
+
     /**
      * Default constructor
      * @param userAgent user agent
@@ -55,7 +56,7 @@
     protected Configuration getRendererConfig(String mimeType) {
         return super.getConfig(mimeType);
     }
-    
+
     /**
      * {@inheritDoc}
      */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFConstants.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFConstants.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFConstants.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFConstants.java Tue Oct 27 19:07:52 2009
@@ -50,4 +50,6 @@
     String EL_BORDER_RECT = "border-rect";
     String EL_FONT = "font";
     String EL_TEXT = "text";
+    /** Parent element of the logical structure tree. */
+    String EL_STRUCTURE_TREE = "structure-tree";
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFContext.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFContext.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFContext.java Tue Oct 27 19:07:52 2009
@@ -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,10 @@
     /** foreign attributes: Map<QName, Object> */
     private Map foreignAttributes = Collections.EMPTY_MAP;
 
+    private Locale language;
+
+    private String structurePointer;
+
     /**
      * Main constructor.
      * @param ua the user agent
@@ -108,4 +113,46 @@
         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.
+     * @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;
+    }
+
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFParser.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFParser.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFParser.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFParser.java Tue Oct 27 19:07:52 2009
@@ -25,6 +25,7 @@
 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;
@@ -34,7 +35,6 @@
 
 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;
@@ -46,6 +46,8 @@
 
 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;
 import org.apache.fop.fo.ElementMappingRegistry;
@@ -59,6 +61,7 @@
 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;
 
 /**
@@ -73,6 +76,15 @@
     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
@@ -140,6 +152,26 @@
 
         private ContentHandler navParser;
 
+        private StructureTreeBuilder structureTreeBuilder;
+
+        private ContentHandler structureTreeBuilderWrapper;
+
+        private Attributes pageSequenceAttributes;
+
+        private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {
+
+            private StructureTreeBuilderWrapper()
+                    throws SAXException {
+                super(structureTreeBuilder.getHandlerForNextPageSequence());
+            }
+
+            public void endDocument() throws SAXException {
+                super.endDocument();
+                startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
+                pageSequenceAttributes = null;
+            }
+        }
+
         public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
                 ElementMappingRegistry elementMappingRegistry) {
             this.documentHandler = documentHandler;
@@ -163,6 +195,11 @@
             elementHandlers.put(EL_LINE, new LineHandler());
             elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
             elementHandlers.put(EL_IMAGE, new ImageHandler());
+
+            if (userAgent.isAccessibilityEnabled()) {
+                structureTreeBuilder = new StructureTreeBuilder(tFactory);
+                userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
+            }
         }
 
         private void establishForeignAttributes(Map foreignAttributes) {
@@ -173,31 +210,50 @@
             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 {
             if (delegate != null) {
-                //delegateStack.push(qName);
                 delegateDepth++;
                 delegate.startElement(uri, localName, qName, attributes);
             } 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()) {
+                        pageSequenceAttributes = new AttributesImpl(attributes);
+                        structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
+                    } else if (localName.equals(EL_STRUCTURE_TREE)) {
+                        if (userAgent.isAccessibilityEnabled()) {
+                            delegate = structureTreeBuilderWrapper;
+                        } else {
+                            /* Delegate to a handler that does nothing */
+                            delegate = new DefaultHandler();
                         }
-                    } else if ("extension-attachments".equals(localName)) {
-                        //TODO implement me
+                        delegateDepth++;
+                        delegate.startDocument();
+                        delegate.startElement(uri, localName, qName, attributes);
                     } else {
-                        handled = false;
+                        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)) {
                     if (this.navParser == null) {
@@ -241,6 +297,25 @@
             }
         }
 
+        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
@@ -352,6 +427,11 @@
 
             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);
@@ -360,6 +440,7 @@
 
             public void endElement() throws IFException {
                 documentHandler.endPageSequence();
+                documentHandler.getContext().setLanguage(null);
             }
 
         }
@@ -484,7 +565,9 @@
                 s = lastAttributes.getValue("word-spacing");
                 int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
                 int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
+                setStructurePointer(lastAttributes);
                 painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
+                resetStructurePointer();
             }
 
             public boolean ignoreCharacters() {
@@ -579,6 +662,7 @@
                 int height = Integer.parseInt(lastAttributes.getValue("height"));
                 Map foreignAttributes = getForeignAttributes(lastAttributes);
                 establishForeignAttributes(foreignAttributes);
+                setStructurePointer(lastAttributes);
                 if (foreignObject != null) {
                     painter.drawImage(foreignObject,
                             new Rectangle(x, y, width, height));
@@ -592,6 +676,7 @@
                     painter.drawImage(uri, new Rectangle(x, y, width, height));
                 }
                 resetForeignAttributes();
+                resetStructurePointer();
                 inForeignObject = false;
             }
 
@@ -632,11 +717,7 @@
             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) {
@@ -649,6 +730,13 @@
             return foreignAttributes;
         }
 
+        private void setStructurePointer(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) {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFRenderer.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFRenderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFRenderer.java Tue Oct 27 19:07:52 2009
@@ -30,6 +30,7 @@
 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 @@
         try {
             if (this.inPageSequence) {
                 documentHandler.endPageSequence();
+                documentHandler.getContext().setLanguage(null);
             } else {
                 if (this.documentMetadata == null) {
                     this.documentMetadata = createDefaultDocumentMetadata();
@@ -502,6 +504,7 @@
                 this.inPageSequence = true;
             }
             establishForeignAttributes(pageSequence.getForeignAttributes());
+            documentHandler.getContext().setLanguage(toLocale(pageSequence));
             documentHandler.startPageSequence(null);
             resetForeignAttributes();
             processExtensionAttachments(pageSequence);
@@ -510,6 +513,17 @@
         }
     }
 
+    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);
@@ -604,6 +618,14 @@
         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);
@@ -824,17 +846,20 @@
             currentIPPosition = saveIP;
             currentBPPosition = saveBP;
 
-            currentBPPosition += (int)(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} */
@@ -892,6 +917,7 @@
         // 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();
@@ -935,6 +961,7 @@
 
         // warn if link trait found but not allowed, else create link
         if (linkTraitFound) {
+            action.setStructurePointer(ptr);  // used for accessibility
             Link link = new Link(action, ipRect);
             this.deferredLinks.add(link);
         }
@@ -969,6 +996,8 @@
 
         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);
@@ -990,6 +1019,7 @@
 
         textUtil.flush();
         renderTextDecoration(tf, size, text, bl, rx);
+        resetStructurePointer();
     }
 
     /** {@inheritDoc} */
@@ -1060,10 +1090,10 @@
         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;
 
         void addChar(char ch) {
             text.append(ch);

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializer.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializer.java Tue Oct 27 19:07:52 2009
@@ -27,16 +27,19 @@
 import java.awt.geom.AffineTransform;
 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.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;
@@ -60,6 +63,7 @@
         implements IFConstants, IFPainter, IFDocumentNavigationHandler {
 
     private IFDocumentHandler mimicHandler;
+    private int pageSequenceIndex; // used for accessibility
 
     /** Holds the intermediate format state */
     private IFState state;
@@ -210,8 +214,23 @@
             if (id != null) {
                 atts.addAttribute(XML_NAMESPACE, "id", "xml:id", XMLUtil.CDATA, id);
             }
+            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()) {
+                StructureTree structureTree = getUserAgent().getStructureTree();
+                handler.startElement(EL_STRUCTURE_TREE); // add structure tree
+                NodeList nodes = structureTree.getPageSequence(pageSequenceIndex++);
+                for (int i = 0, n = nodes.getLength(); i < n; i++) {
+                    Node node = nodes.item(i);
+                    new DOM2SAX(handler).writeFragment(node);
+                }
+                handler.endElement(EL_STRUCTURE_TREE);
+            }
         } catch (SAXException e) {
             throw new IFException("SAX error in startPageSequence()", e);
         }
@@ -392,13 +411,14 @@
             addAttribute(atts, "width", Integer.toString(rect.width));
             addAttribute(atts, "height", Integer.toString(rect.height));
             addForeignAttributes(atts);
+            addStructurePointerAttribute(atts);
             handler.element(EL_IMAGE, atts);
         } catch (SAXException e) {
             throw new IFException("SAX error in startGroup()", e);
         }
     }
 
-    private void addForeignAttributes(AttributesImpl atts) {
+    private void addForeignAttributes(AttributesImpl atts) throws SAXException {
         Map foreignAttributes = getContext().getForeignAttributes();
         if (!foreignAttributes.isEmpty()) {
             Iterator iter = foreignAttributes.entrySet().iterator();
@@ -418,6 +438,7 @@
             addAttribute(atts, "width", Integer.toString(rect.width));
             addAttribute(atts, "height", Integer.toString(rect.height));
             addForeignAttributes(atts);
+            addStructurePointerAttribute(atts);
             handler.startElement(EL_IMAGE, atts);
             new DOM2SAX(handler).writeDocument(doc, true);
             handler.endElement(EL_IMAGE);
@@ -531,6 +552,7 @@
             if (dx != null) {
                 addAttribute(atts, "dx", IFUtil.toString(dx));
             }
+            addStructurePointerAttribute(atts);
             handler.startElement(EL_TEXT, atts);
             char[] chars = text.toCharArray();
             handler.characters(chars, 0, chars.length);
@@ -617,7 +639,8 @@
     }
 
     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);
     }
 
@@ -625,6 +648,13 @@
         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();
@@ -696,6 +726,9 @@
         AttributesImpl atts = new AttributesImpl();
         atts.addAttribute(null, "rect", "rect",
                 XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
+        if (getUserAgent().isAccessibilityEnabled()) {
+            addAttribute(atts, "ptr", link.getAction().getStructurePointer());
+        }
         try {
             handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);
             serializeXMLizable(link.getAction());

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java Tue Oct 27 19:07:52 2009
@@ -27,6 +27,7 @@
 public abstract class AbstractAction implements XMLizable {
 
     private String id;
+    private String structurePointer;
 
     /**
      * Sets an ID to make the action referencable.
@@ -45,6 +46,22 @@
     }
 
     /**
+     * Sets the structure element corresponding to this action.
+     * @param structurePointer a reference to the structure element
+     */
+    public void setStructurePointer(String structurePointer) {
+        this.structurePointer = structurePointer;
+    }
+
+    /**
+     * Returns the structure element corresponding to this action.
+     * @return the reference to the structure element
+     */
+    public String getStructurePointer() {
+        return structurePointer;
+    }
+
+    /**
      * Indicates whether the action has an ID and is therefore referencable.
      * @return true if the action has an ID
      */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationHandler.java Tue Oct 27 19:07:52 2009
@@ -48,6 +48,8 @@
 
     private IFDocumentNavigationHandler navHandler;
 
+    private String structurePointer;
+
     /**
      * Main constructor.
      * @param navHandler the navigation handler that will receive the events
@@ -96,6 +98,7 @@
                     throw new SAXException(localName + " must be the root element!");
                 }
                 Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect");
+                structurePointer = attributes.getValue("ptr");
                 Link link = new Link(null, targetRect);
                 objectStack.push(link);
             } else if (GOTO_XY.getLocalName().equals(localName)) {
@@ -118,6 +121,9 @@
                     }
                     action = new GoToXYAction(id, pageIndex, location);
                 }
+                if (structurePointer != null) {
+                    action.setStructurePointer(structurePointer);
+                }
                 objectStack.push(action);
             } else if (GOTO_URI.getLocalName().equals(localName)) {
                 String id = attributes.getValue("id");
@@ -128,6 +134,9 @@
                 if (id != null) {
                     action.setID(id);
                 }
+                if (structurePointer != null) {
+                    action.setStructurePointer(structurePointer);
+                }
                 objectStack.push(action);
             } else {
                 throw new SAXException(

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFContentGenerator.java Tue Oct 27 19:07:52 2009
@@ -56,6 +56,8 @@
     /** Text generation utility holding the current font status */
     protected PDFTextUtil textutil;
 
+    private boolean inMarkedContentSequence;
+    private boolean inArtifactMode;
 
     /**
      * Main constructor. Creates a new PDF stream and additional helper classes for text painting
@@ -153,6 +155,40 @@
         currentStream.add("q\n");
     }
 
+    /** {@inheritDoc} */
+    protected void saveGraphicsState(String structElemType, int sequenceNum) {
+        endTextObject();
+        currentState.save();
+        beginMarkedContentSequence(structElemType, sequenceNum);
+        currentStream.add("q\n");
+    }
+
+    /**
+     * 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 mcid    Sequence number
+     */
+    protected void beginMarkedContentSequence(String structElemType, int mcid) {
+        assert !this.inMarkedContentSequence;
+        assert !this.inArtifactMode;
+        if (structElemType != null) {
+            currentStream.add(structElemType + " <</MCID " + String.valueOf(mcid) + ">>\n"
+                    + "BDC\n");
+        } else {
+            currentStream.add("/Artifact\nBMC\n");
+            this.inArtifactMode = true;
+        }
+        this.inMarkedContentSequence = true;
+    }
+
+    void endMarkedContentSequence() {
+        currentStream.add("EMC\n");
+        this.inMarkedContentSequence = false;
+        this.inArtifactMode = false;
+    }
+
     /**
      * Restored the graphics state valid before the previous {@link #saveGraphicsState()}.
      * @param popState true if the state should also be popped, false if only the PDF command
@@ -166,11 +202,42 @@
         }
     }
 
-    /** {@inheritDoc} */
+    /**
+     * Same as {@link #restoreGraphicsState(boolean)}, with <code>true</code> as
+     * a parameter.
+     */
     protected void restoreGraphicsState() {
         restoreGraphicsState(true);
     }
 
+    /**
+     * Same as {@link #restoreGraphicsState()}, additionally ending the current
+     * marked content sequence if any.
+     */
+    protected void restoreGraphicsStateAccess() {
+        endTextObject();
+        currentStream.add("Q\n");
+        if (this.inMarkedContentSequence) {
+            endMarkedContentSequence();
+        }
+        currentState.restore();
+    }
+
+    /**
+     * 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();
+        endMarkedContentSequence();
+        beginMarkedContentSequence(structElemType, mcid);
+        textutil.beginTextObject();
+    }
+
     /** Indicates the beginning of a text object. */
     protected void beginTextObject() {
         if (!textutil.isInTextObject()) {
@@ -178,9 +245,27 @@
         }
     }
 
+    /**
+     * 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 beginTextObject(String structElemType, int mcid) {
+        if (!textutil.isInTextObject()) {
+            beginMarkedContentSequence(structElemType, mcid);
+            textutil.beginTextObject();
+        }
+    }
+
     /** Indicates the end of a text object. */
     protected void endTextObject() {
         if (textutil.isInTextObject()) {
+            if (this.inMarkedContentSequence) {
+                endMarkedContentSequence();
+            }
             textutil.endTextObject();
         }
     }
@@ -326,5 +411,28 @@
         restoreGraphicsState();
     }
 
+    /**
+     * 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 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) {
+        saveGraphicsState(structElemType, mcid);
+        add(format(w) + " 0 0 "
+                          + format(-h) + " "
+                          + format(x) + " "
+                          + format(y + h)
+                          + " cm\n" + xobj.getName() + " Do\n");
+        restoreGraphicsStateAccess();
+    }
 
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java Tue Oct 27 19:07:52 2009
@@ -28,6 +28,8 @@
 import java.io.IOException;
 import java.util.Map;
 
+import org.w3c.dom.NodeList;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -50,6 +52,7 @@
 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;
 
 /**
  * {@link IFDocumentHandler} implementation that produces PDF.
@@ -59,6 +62,12 @@
     /** logging instance */
     private static Log log = LogFactory.getLog(PDFDocumentHandler.class);
 
+    private int pageSequenceIndex;
+
+    private boolean accessEnabled;
+
+    private PDFLogicalStructureHandler logicalStructureHandler;
+
     /** the PDF Document being created */
     protected PDFDocument pdfDoc;
 
@@ -86,7 +95,7 @@
     /** Used for bookmarks/outlines. */
     protected Map pageReferences = new java.util.HashMap();
 
-    private PDFDocumentNavigationHandler documentNavigationHandler
+    private final PDFDocumentNavigationHandler documentNavigationHandler
             = new PDFDocumentNavigationHandler(this);
 
     /**
@@ -97,7 +106,7 @@
 
     /** {@inheritDoc} */
     public boolean supportsPagesOutOfOrder() {
-        return true;
+        return !accessEnabled;
     }
 
     /** {@inheritDoc} */
@@ -125,11 +134,20 @@
         return this.pdfUtil;
     }
 
+    PDFLogicalStructureHandler getLogicalStructureHandler() {
+        return logicalStructureHandler;
+    }
+
     /** {@inheritDoc} */
     public void startDocument() throws IFException {
         super.startDocument();
         try {
             this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream);
+            this.accessEnabled = getUserAgent().isAccessibilityEnabled();
+            if (accessEnabled) {
+                pdfDoc.getRoot().makeTagged();
+                logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
+            }
         } catch (IOException e) {
             throw new IFException("I/O error in startDocument()", e);
         }
@@ -145,7 +163,6 @@
         try {
             pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
             pdfDoc.outputTrailer(this.outputStream);
-
             this.pdfDoc = null;
 
             pdfResources = null;
@@ -160,7 +177,18 @@
 
     /** {@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 (accessEnabled) {
+            NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
+            logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage());
+        }
     }
 
     /** {@inheritDoc} */
@@ -198,13 +226,17 @@
                 toPointAndScale(cropBox, scaleX, scaleY),
                 toPointAndScale(bleedBox, scaleX, scaleY),
                 toPointAndScale(trimBox, scaleX, scaleY));
+        if (accessEnabled) {
+            logicalStructureHandler.startPage(currentPage);
+        }
 
         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);
         // 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,
                 (scaleY * size.height) / 1000f);
@@ -221,7 +253,7 @@
 
     /** {@inheritDoc} */
     public IFPainter startPageContent() throws IFException {
-        return new PDFPainter(this);
+        return new PDFPainter(this, logicalStructureHandler);
     }
 
     /** {@inheritDoc} */
@@ -231,6 +263,9 @@
 
     /** {@inheritDoc} */
     public void endPage() throws IFException {
+        if (accessEnabled) {
+            logicalStructureHandler.endPage();
+        }
         try {
             this.documentNavigationHandler.commit();
             this.pdfDoc.registerObject(generator.getStream());
@@ -267,8 +302,8 @@
 
     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();

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java Tue Oct 27 19:07:52 2009
@@ -47,10 +47,10 @@
  */
 public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler {
 
-    private PDFDocumentHandler documentHandler;
+    private final 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 +111,11 @@
         PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
                 targetRect2D, pdfAction);
         if (pdfLink != null) {
+            String ptr = link.getAction().getStructurePointer();
+            if (documentHandler.getUserAgent().isAccessibilityEnabled()
+                    && ptr != null && ptr.length() > 0) {
+                documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr);
+            }
             documentHandler.currentPage.addAnnotation(pdfLink);
         }
     }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerGraphics2D.java Tue Oct 27 19:07:52 2009
@@ -35,6 +35,7 @@
 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 @@
                 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 @@
         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 @@
         imageG2D.getGraphics2DImagePainter().paint(graphics, area);
 
         generator.add(graphics.getString());
-        generator.restoreGraphicsState();
+        if (accessibilityEnabled) {
+            generator.restoreGraphicsStateAccess();
+        } else {
+            generator.restoreGraphicsState();
+        }
         generator.comment("G2D end");
     }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawJPEG.java Tue Oct 27 19:07:52 2009
@@ -34,6 +34,7 @@
 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.
@@ -82,7 +83,12 @@
         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().isAccessibilityEnabled()) {
+            MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
+            generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid);
+        } else {
+            generator.placeImage(x, y, w, h, xobj);
+        }
     }
 
     /** {@inheritDoc} */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRenderedImage.java Tue Oct 27 19:07:52 2009
@@ -34,6 +34,7 @@
 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.
@@ -83,7 +84,12 @@
         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().isAccessibilityEnabled()) {
+            MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
+            generator.placeImage(x, y, w, h, xobj, mci.tag, mci.mcid);
+        } else {
+            generator.placeImage(x, y, w, h, xobj);
+        }
     }
 
     /** {@inheritDoc} */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerSVG.java Tue Oct 27 19:07:52 2009
@@ -40,6 +40,7 @@
 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;
@@ -101,8 +102,8 @@
         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 +122,10 @@
          */
         generator.comment("SVG setup");
         generator.saveGraphicsState();
+        if (context.getUserAgent().isAccessibilityEnabled()) {
+            MarkedContentInfo mci = pdfContext.getMarkedContentInfo();
+            generator.beginMarkedContentSequence(mci.tag, mci.mcid);
+        }
         generator.setColor(Color.black, false);
         generator.setColor(Color.black, true);
 
@@ -168,7 +173,11 @@
             eventProducer.svgRenderingError(this, e, image.getInfo().getOriginalURI());
         }
         generator.getState().restore();
-        generator.restoreGraphicsState();
+        if (context.getUserAgent().isAccessibilityEnabled()) {
+            generator.restoreGraphicsStateAccess();
+        } else {
+            generator.restoreGraphicsState();
+        }
         generator.comment("SVG end");
     }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFPainter.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFPainter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFPainter.java Tue Oct 27 19:07:52 2009
@@ -29,9 +29,6 @@
 
 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.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,26 +54,33 @@
  */
 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;
+
+    private MarkedContentInfo imageMCI;
+
+    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();
+        accessEnabled = this.getUserAgent().isAccessibilityEnabled();
     }
 
     /** {@inheritDoc} */
@@ -122,22 +127,36 @@
     }
 
     /** {@inheritDoc} */
-    public void drawImage(String uri, Rectangle rect) throws IFException {
+    public void drawImage(String uri, Rectangle rect)
+            throws IFException {
         PDFXObject xobject = getPDFDoc().getXObject(uri);
         if (xobject != null) {
-            placeImage(rect, xobject);
-            return;
+            if (accessEnabled) {
+                String ptr = getContext().getStructurePointer();
+                prepareImageMCID(ptr);
+                placeImageAccess(rect, xobject);
+            } else {
+                placeImage(rect, xobject);
+            }
+        } else {
+            if (accessEnabled) {
+                String ptr = getContext().getStructurePointer();
+                prepareImageMCID(ptr);
+            }
+            drawImageUsingURI(uri, rect);
+            flushPDFDoc();
         }
+    }
 
-        drawImageUsingURI(uri, rect);
-
-        flushPDFDoc();
+    private void prepareImageMCID(String ptr) {
+        imageMCI = logicalStructureHandler.addImageContentItem(ptr);
     }
 
     /** {@inheritDoc} */
     protected RenderingContext createRenderingContext() {
         PDFRenderingContext pdfContext = new PDFRenderingContext(
                 getUserAgent(), generator, this.documentHandler.currentPage, getFontInfo());
+        pdfContext.setMarkedContentInfo(imageMCI);
         return pdfContext;
     }
 
@@ -158,11 +177,31 @@
                           + " 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(imageMCI.tag, imageMCI.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 {
+        if (accessEnabled) {
+            String ptr = getContext().getStructurePointer();
+            prepareImageMCID(ptr);
+        }
         drawImageUsingDocument(doc, rect);
-
         flushPDFDoc();
     }
 
@@ -253,10 +292,22 @@
     }
 
     /** {@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)
             throws IFException {
-        generator.updateColor(state.getTextColor(), true, null);
-        generator.beginTextObject();
+        if (accessEnabled) {
+            String ptr = getContext().getStructurePointer();
+            MarkedContentInfo mci = logicalStructureHandler.addTextContentItem(ptr);
+            if (generator.getTextUtil().isInTextObject()) {
+                generator.separateTextElements(mci.tag, mci.mcid);
+            }
+            generator.updateColor(state.getTextColor(), true, null);
+            generator.beginTextObject(mci.tag, mci.mcid);
+        } 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 +328,7 @@
         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();

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderer.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderer.java Tue Oct 27 19:07:52 2009
@@ -31,8 +31,12 @@
 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.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.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 @@
      * 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 @@
     /** Image handler registry */
     private final PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
 
+    private boolean accessEnabled;
+
+    private PDFLogicalStructureHandler logicalStructureHandler;
+
+    private int pageSequenceIndex;
+
+    /** Reference in the structure tree to the image being rendered. */
+    private String imageReference;
 
     /**
      * create the PDF renderer
@@ -204,6 +219,7 @@
     public void setUserAgent(FOUserAgent agent) {
         super.setUserAgent(agent);
         this.pdfUtil = new PDFRenderingUtil(getUserAgent());
+        accessEnabled = agent.isAccessibilityEnabled();
     }
 
     PDFRenderingUtil getPDFUtil() {
@@ -225,6 +241,10 @@
         }
         ostream = stream;
         this.pdfDoc = pdfUtil.setupPDFDocument(stream);
+        if (accessEnabled) {
+            pdfDoc.getRoot().makeTagged();
+            logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
+        }
     }
 
     /**
@@ -274,8 +294,7 @@
      * {@inheritDoc}
      */
     public boolean supportsOutOfOrder() {
-        //return false;
-        return true;
+        return !accessEnabled;
     }
 
     /**
@@ -394,17 +413,24 @@
                 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(pageSequenceIndex++);
+            logicalStructureHandler.processStructureTree(nodes, language);
+        }
     }
 
     /**
@@ -457,6 +483,10 @@
         }
         currentPageRef = currentPage.referencePDF();
 
+        if (accessEnabled) {
+            logicalStructureHandler.startPage(currentPage);
+        }
+
         Rectangle bounds = page.getViewArea();
         pageHeight = bounds.height;
 
@@ -474,6 +504,10 @@
 
         super.renderPage(page);
 
+        if (accessEnabled) {
+            logicalStructureHandler.endPage();
+        }
+
         this.pdfDoc.registerObject(generator.getStream());
         currentPage.setContents(generator.getStream());
         PDFAnnotList annots = currentPage.getAnnotations();
@@ -903,11 +937,22 @@
                          + 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);
+        imageReference = null;
+    }
+
     private Typeface getTypeface(String fontName) {
         Typeface tf = (Typeface) fontInfo.getFonts().get(fontName);
         if (tf instanceof LazyFont) {
@@ -922,7 +967,16 @@
         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.beginTextObject(mci.tag, mci.mcid);
+        } else {
+            beginTextObject();
+        }
 
         String fontName = getInternalFontNameForArea(text);
         int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
@@ -1178,13 +1232,22 @@
      * @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 @@
         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.
@@ -1272,5 +1347,9 @@
     public void setEncryptionParams(PDFEncryptionParams encryptionParams) {
         this.pdfUtil.setEncryptionParams(encryptionParams);
     }
+
+    MarkedContentInfo addCurrentImageToStructureTree() {
+        return logicalStructureHandler.addImageContentItem(imageReference);
+    }
 }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingContext.java Tue Oct 27 19:07:52 2009
@@ -25,6 +25,7 @@
 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,6 +35,7 @@
     private PDFContentGenerator generator;
     private FontInfo fontInfo;
     private PDFPage page;
+    private MarkedContentInfo mci;
 
     /**
      * Main constructor.
@@ -79,4 +81,11 @@
         return this.fontInfo;
     }
 
+    void setMarkedContentInfo(MarkedContentInfo mci) {
+        this.mci = mci;
+    }
+
+    MarkedContentInfo getMarkedContentInfo() {
+        return mci;
+    }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFRenderingUtil.java Tue Oct 27 19:07:52 2009
@@ -37,6 +37,7 @@
 import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
 import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
 
+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;
@@ -109,7 +110,7 @@
 
     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 @@
         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(Accessibility.ACCESSIBILITY, Boolean.TRUE);
+        }
         s = (String)userAgent.getRendererOptions().get(PDF_X_MODE);
         if (s != null) {
             this.pdfXMode = PDFXMode.valueOf(s);

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/txt/TXTRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/txt/TXTRenderer.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/txt/TXTRenderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/txt/TXTRenderer.java Tue Oct 27 19:07:52 2009
@@ -28,6 +28,8 @@
 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.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.

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/xml/XMLRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/xml/XMLRenderer.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/xml/XMLRenderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/xml/XMLRenderer.java Tue Oct 27 19:07:52 2009
@@ -34,7 +34,8 @@
 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;
@@ -86,6 +87,7 @@
 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 +107,8 @@
     /** If not null, the XMLRenderer will mimic another renderer by using its font setup. */
     protected Renderer mimic;
 
+    private int pageSequenceIndex;
+
     /**
      * Creates a new XML renderer.
      */
@@ -440,6 +444,20 @@
         }
         transferForeignObjects(pageSequence);
         startElement("pageSequence", atts);
+        if (this.getUserAgent().isAccessibilityEnabled()) {
+            String structureTreeElement = "structureTree";
+            startElement(structureTreeElement);
+            NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
+            for (int i = 0, n = nodes.getLength(); i < n; i++) {
+                Node node = nodes.item(i);
+                try {
+                    new DOM2SAX(handler).writeFragment(node);
+                } catch (SAXException e) {
+                    handleSAXException(e);
+                }
+            }
+            endElement(structureTreeElement);
+        }
         handleExtensionAttachments(pageSequence.getExtensionAttachments());
         LineArea seqTitle = pageSequence.getTitle();
         if (seqTitle != null) {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DOM2SAX.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DOM2SAX.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DOM2SAX.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/DOM2SAX.java Tue Oct 27 19:07:52 2009
@@ -26,7 +26,6 @@
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
-
 import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.ext.LexicalHandler;
@@ -79,6 +78,15 @@
     }
 
     /**
+     * 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
      * only if the prefix is unknown or it is mapped to a different URI.
      */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/util/XMLUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/util/XMLUtil.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/util/XMLUtil.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/util/XMLUtil.java Tue Oct 27 19:07:52 2009
@@ -21,6 +21,7 @@
 
 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 @@
         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]);
+        }
+    }
+
 }

Modified: xmlgraphics/fop/trunk/src/sandbox/org/apache/fop/render/svg/SVGPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/sandbox/org/apache/fop/render/svg/SVGPainter.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/sandbox/org/apache/fop/render/svg/SVGPainter.java (original)
+++ xmlgraphics/fop/trunk/src/sandbox/org/apache/fop/render/svg/SVGPainter.java Tue Oct 27 19:07:52 2009
@@ -324,8 +324,9 @@
     }
 
     /** {@inheritDoc} */
-    public void drawText(int x, int y, int letterSpacing, int wordSpacing, int[] dx, String text)
-                throws IFException {
+
+    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();

Modified: xmlgraphics/fop/trunk/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/status.xml?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/status.xml (original)
+++ xmlgraphics/fop/trunk/status.xml Tue Oct 27 19:07:52 2009
@@ -58,6 +58,9 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Renderers" dev="JM,VH" type="add" fixes-bug="46705" due-to="Jost Klopfstein">
+        Added basic accessibility and Tagged PDF support. 
+      </action>
       <action context="Code" dev="JM" type="add">
         Added support for encoding CMYK bitmap images (IOCA FS45) and TIFF images as embedded objects.
       </action>

Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/PDFAConformanceTestCase.java Tue Oct 27 19:07:52 2009
@@ -99,7 +99,8 @@
         foFile = new File(foBaseDir, "with-cmyk-images.fo");
         try {
             convertFO(foFile, getUserAgent(), dumpPDF);
-            fail("Expected PDFConformanceException. PDF/A-1 does not allow PostScript XObjects.");
+            fail("Expected PDFConformanceException."
+                    + " PDF/A-1 does not allow mixing DeviceRGB and DeviceCMYK.");
         } catch (PDFConformanceException e) {
             //Good!
         }

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/foreign-attributes.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/foreign-attributes.xml?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/foreign-attributes.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/foreign-attributes.xml Tue Oct 27 19:07:52 2009
@@ -31,9 +31,6 @@
       </fo:layout-master-set>
       <fo:page-sequence master-reference="normal">
         <fo:flow flow-name="xsl-region-body">
-          <fo:block id="eg">
-            <fo:external-graphic src="../../resources/images/bgimg300dpi.jpg" fox:alt="description"/>
-          </fo:block>
           <fo:block id="bl">
             <fo:basic-link external-destination="url(http://xmlgraphics.apache.org/fop/)" fox:blah="fop">FOP</fo:basic-link>
           </fo:block>
@@ -43,7 +40,6 @@
   </fo>
   <checks xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
     <eval expected="bar" xpath="//pageViewport[1]/@fox:foo"/>
-    <eval expected="description" xpath="//block[@prod-id='eg']//image/@fox:alt"/>
     <!--eval expected="fop" xpath="//block[@prod-id='bl']/inlineparent/@fox:blah"/> NYI -->
   </checks>
 </testcase>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/page-sequence_language.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/page-sequence_language.xml?rev=830293&r1=830292&r2=830293&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/page-sequence_language.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/page-sequence_language.xml Tue Oct 27 19:07:52 2009
@@ -65,4 +65,10 @@
     <eval expected="de" xpath="/areaTree/pageSequence[4]/@language"/>
     <true xpath="not(boolean(/areaTree/pageSequence[4]/@country))"/>
   </checks>
+  <if-checks xmlns:if="http://xmlgraphics.apache.org/fop/intermediate">
+    <eval expected="en" xpath="//if:page-sequence[1]/@xml:lang"/>
+    <eval expected="en-US" xpath="//if:page-sequence[2]/@xml:lang"/>
+    <eval expected="de-CH" xpath="//if:page-sequence[3]/@xml:lang"/>
+    <eval expected="de" xpath="//if:page-sequence[4]/@xml:lang"/>
+  </if-checks>
 </testcase>



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org