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 ph...@apache.org on 2012/02/10 17:51:14 UTC

svn commit: r1242848 [3/5] - in /xmlgraphics/fop/trunk: ./ src/documentation/intermediate-format-ng/ src/java/org/apache/fop/accessibility/ src/java/org/apache/fop/accessibility/fo/ src/java/org/apache/fop/afp/apps/ src/java/org/apache/fop/afp/parser/ ...

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFDocument.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFDocument.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFDocument.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFDocument.java Fri Feb 10 16:51:08 2012
@@ -350,25 +350,6 @@ public class PDFDocument {
     }
 
     /**
-     * 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.
      *
      * @return the {@link PDFInfo} object

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -133,8 +133,12 @@ public class PDFProfile {
 
     //---------=== Info and validation methods ===---------
 
+    private String format(String pattern, Object[] args) {
+        return MessageFormat.format(pattern, args);
+    }
+
     private String format(String pattern, Object arg) {
-        return MessageFormat.format(pattern, new Object[] {arg});
+        return format(pattern, new Object[] {arg});
     }
 
     /** Checks if encryption is allowed. */

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -21,6 +21,9 @@ package org.apache.fop.pdf;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Locale;
+
+import org.apache.fop.util.LanguageTags;
 
 /**
  * Class representing a Root (/Catalog) object.
@@ -69,6 +72,7 @@ public class PDFRoot extends PDFDictiona
         setObjectNumber(objnum);
         put("Type", new PDFName("Catalog"));
         setRootPages(pages);
+        setLanguage("x-unknown");
     }
 
     /** {@inheritDoc} */
@@ -251,13 +255,17 @@ public class PDFRoot extends PDFDictiona
     }
 
     /**
-     * Sets the language identifier of the document.
-     * @param lang the language identifier of the document.
+     * Sets the locale of the document.
+     * @param locale the locale of the document.
      */
-    public void setLanguage(String lang) {
-        if (lang == null) {
-            throw new NullPointerException("lang must not be null");
+    public void setLanguage(Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException("locale must not be null");
         }
+        setLanguage(LanguageTags.toLanguageTag(locale));
+    }
+
+    private void setLanguage(String lang) {
         put("Lang", lang);
     }
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFStructElem.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFStructElem.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFStructElem.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFStructElem.java Fri Feb 10 16:51:08 2012
@@ -19,18 +19,29 @@
 
 package org.apache.fop.pdf;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
-import org.apache.fop.util.XMLUtil;
+import org.apache.fop.accessibility.StructureTreeElement;
+import org.apache.fop.util.LanguageTags;
 
 /**
  * Class representing a PDF Structure Element.
  */
-public class PDFStructElem extends PDFDictionary {
+public class PDFStructElem extends PDFDictionary implements StructureTreeElement {
 
     private PDFStructElem parentElement;
 
     /**
+     * Elements to be added to the kids array.
+     */
+    protected List<PDFObject> kids;
+
+    /**
      * Creates a new structure element.
      *
      * @param parent parent of this element
@@ -57,21 +68,12 @@ public class PDFStructElem extends PDFDi
 
     /** {@inheritDoc} */
     public void setParent(PDFObject parent) {
-        if (parent != null) {
+        if (parent != null && parent.hasObjectNumber()) {
            put("P", new PDFReference(parent));
         }
     }
 
     /**
-     * Returns the kids of this structure element.
-     *
-     * @return the value of the K entry
-     */
-    private PDFArray getKids() {
-        return (PDFArray) get("K");
-    }
-
-    /**
      * Add a kid to this structure element. This element will then add itself to
      * its parent structure element if it has not already, and so will the
      * parent, and so on.
@@ -79,24 +81,10 @@ public class PDFStructElem extends PDFDi
      * @param kid element to be added
      */
     public void addKid(PDFObject kid) {
-        PDFArray kids = getKids();
         if (kids == null) {
-            kids = new PDFArray();
-            put("K", kids);
+            kids = new ArrayList<PDFObject>();
         }
         kids.add(kid);
-        joinHierarchy();
-    }
-
-    private boolean containsKid(PDFObject kid) {
-        PDFArray kids = getKids();
-        return kids != null && kids.contains(kid);
-    }
-
-    private void joinHierarchy() {
-        if (parentElement != null && !parentElement.containsKid(this)) {
-            parentElement.addKid(this);
-        }
     }
 
     /**
@@ -109,7 +97,6 @@ public class PDFStructElem extends PDFDi
      */
     public void setMCIDKid(int mcid) {
         put("K", mcid);
-        joinHierarchy();
     }
 
     /**
@@ -127,7 +114,7 @@ public class PDFStructElem extends PDFDi
      * @return the value of the S entry
      */
     public PDFName getStructureType() {
-        return (PDFName)get("S");
+        return (PDFName) get("S");
     }
 
     /**
@@ -145,7 +132,7 @@ public class PDFStructElem extends PDFDi
      * @param language a value for the Lang entry
      */
     public void setLanguage(Locale language) {
-        setLanguage(XMLUtil.toRFC3066(language));
+        setLanguage(LanguageTags.toLanguageTag(language));
     }
 
     /**
@@ -154,6 +141,71 @@ public class PDFStructElem extends PDFDi
      * @return the value of the Lang entry (<code>null</code> if no language was specified)
      */
     public String getLanguage() {
-        return (String)get("Lang");
+        return (String) get("Lang");
+    }
+
+    @Override
+    protected void writeDictionary(OutputStream out, StringBuilder textBuffer) throws IOException {
+        attachKids();
+        super.writeDictionary(out, textBuffer);
     }
+
+    /**
+     * Attaches all valid kids to the kids array.
+     *
+     * @return true iff 1+ kids were added to the kids array
+     */
+    protected boolean attachKids() {
+        List<PDFObject> validKids = new ArrayList<PDFObject>();
+        if (kids != null) {
+            for (PDFObject kid : kids) {
+                if (kid instanceof Placeholder)  {
+                    if (((Placeholder) kid).attachKids()) {
+                        validKids.add(kid);
+                    }
+                } else {
+                    validKids.add(kid);
+                }
+            }
+        }
+        boolean kidsAttached = !validKids.isEmpty();
+        if (kidsAttached) {
+            PDFArray array = new PDFArray();
+            for (PDFObject ob : validKids) {
+                array.add(ob);
+            }
+            put("K", array);
+        }
+        return kidsAttached;
+    }
+
+    /**
+     * Class representing a placeholder for a PDF Structure Element.
+     */
+    public static class Placeholder extends PDFStructElem {
+
+        @Override
+        public void outputInline(OutputStream out, StringBuilder textBuffer) throws IOException {
+            if (kids != null) {
+                assert kids.size() > 0;
+                for (int i = 0; i < kids.size(); i++) {
+                    if (i > 0) {
+                        textBuffer.append(' ');
+                    }
+                    Object obj = kids.get(i);
+                    formatObject(obj, out, textBuffer);
+                }
+            }
+        }
+
+        /**
+         * Constructor
+         * @param parent -
+         * @param name -
+         */
+        public Placeholder(PDFObject parent, String name) {
+            super(parent, new PDFName(name));
+        }
+    }
+
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRenderer.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRenderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/AbstractRenderer.java Fri Feb 10 16:51:08 2012
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 
 import org.w3c.dom.Document;
@@ -152,6 +153,10 @@ public abstract class AbstractRenderer
         return false;
     }
 
+    /** {@inheritDoc} */
+    public void setDocumentLocale(Locale locale) {
+    }
+
     /**
      * {@inheritDoc}
      */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/Renderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/Renderer.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/Renderer.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/Renderer.java Fri Feb 10 16:51:08 2012
@@ -22,6 +22,7 @@ package org.apache.fop.render;
 // Java
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.Locale;
 
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
@@ -109,6 +110,12 @@ public interface Renderer {
     boolean supportsOutOfOrder();
 
     /**
+     *
+     * @param locale Locale of the language
+     */
+    void setDocumentLocale(Locale locale);
+
+    /**
      * Tells the renderer to process an item not explicitly placed on the
      * document (e.g., PDF bookmarks).  Note - not all renderers will process
      * all off-document items.

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/AbstractIFDocumentHandler.java Fri Feb 10 16:51:08 2012
@@ -19,6 +19,13 @@
 
 package org.apache.fop.render.intermediate;
 
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
 import org.apache.fop.apps.FOUserAgent;
 
 /**
@@ -53,6 +60,11 @@ public abstract class AbstractIFDocument
     }
 
     /** {@inheritDoc} */
+    public StructureTreeEventHandler getStructureTreeEventHandler() {
+        return DummyStructureTreeEventHandler.INSTANCE;
+    }
+
+    /** {@inheritDoc} */
     public IFDocumentNavigationHandler getDocumentNavigationHandler() {
         return null; //By default, this is not supported
     }
@@ -66,6 +78,10 @@ public abstract class AbstractIFDocument
     }
 
     /** {@inheritDoc} */
+    public void setDocumentLocale(Locale locale) {
+    }
+
+    /** {@inheritDoc} */
     public void startDocumentHeader() throws IFException {
         //nop
     }
@@ -104,5 +120,4 @@ public abstract class AbstractIFDocument
     public void endPageTrailer() throws IFException {
         //nop
     }
-
 }

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -39,6 +39,8 @@ public interface IFConstants extends XML
     String EL_HEADER = "header";
     /** element name trailer */
     String EL_TRAILER = "trailer";
+    /** element name locale */
+    String EL_LOCALE = "locale";
     /** element name page-sequence */
     String EL_PAGE_SEQUENCE = "page-sequence";
     /** element name page */

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.apache.xmlgraphics.util.QName;
 
+import org.apache.fop.accessibility.StructureTreeElement;
 import org.apache.fop.apps.FOUserAgent;
 
 /**
@@ -46,7 +47,7 @@ public class IFContext {
 
     private Locale language;
 
-    private String structurePointer;
+    private StructureTreeElement structureTreeElement;
 
     private String id = "";
 
@@ -132,29 +133,31 @@ public class IFContext {
     }
 
     /**
-     * Sets the structure pointer for the following painted marks. This method is used when
-     * accessibility features are enabled.
-     * @param ptr the structure pointer
+     * Sets the structure tree element to which the subsequently painted marks
+     * will correspond. This method is used when accessibility features are
+     * enabled.
+     *
+     * @param structureTreeElement the structure tree element
      */
-    public void setStructurePointer(String ptr) {
-        this.structurePointer = ptr;
+    public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
+        this.structureTreeElement = structureTreeElement;
     }
 
     /**
-     * Resets the current structure pointer.
-     * @see #setStructurePointer(String)
+     * Resets the current structure tree element.
+     * @see #setStructureTreeElement(String)
      */
-    public void resetStructurePointer() {
-        setStructurePointer(null);
+    public void resetStructureTreeElement() {
+        setStructureTreeElement(null);
     }
 
     /**
-     * Returns the current structure pointer.
-     * @return the structure pointer (or null if no pointer is active)
-     * @see #setStructurePointer(String)
+     * Returns the current structure tree element.
+     * @return the structure tree element (or null if no element is active)
+     * @see #setStructureTreeElement(String)
      */
-    public String getStructurePointer() {
-        return this.structurePointer;
+    public StructureTreeElement getStructureTreeElement() {
+        return this.structureTreeElement;
     }
 
     /**

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFDocumentHandler.java Fri Feb 10 16:51:08 2012
@@ -20,9 +20,11 @@
 package org.apache.fop.render.intermediate;
 
 import java.awt.Dimension;
+import java.util.Locale;
 
 import javax.xml.transform.Result;
 
+import org.apache.fop.accessibility.StructureTreeEventHandler;
 import org.apache.fop.fonts.FontInfo;
 
 /**
@@ -32,6 +34,7 @@ import org.apache.fop.fonts.FontInfo;
  * <p>
  * <pre>
  * startDocument()
+ *   [setDocumentLocale()]
  *   startDocumentHeader()
  *   [handleExtension()]*
  *   endDocumentHeader()
@@ -118,6 +121,11 @@ public interface IFDocumentHandler {
     IFDocumentHandlerConfigurator getConfigurator();
 
     /**
+     * @return the structure tree builder
+     */
+    StructureTreeEventHandler getStructureTreeEventHandler();
+
+    /**
      * Returns a document navigation handler if this feature is supported.
      * @return the document navigation handler or null if not supported
      */
@@ -152,6 +160,11 @@ public interface IFDocumentHandler {
     void endDocument() throws IFException;
 
     /**
+    * @param locale Locale of the document.
+    */
+    void setDocumentLocale(Locale locale);
+
+    /**
      * Indicates the start of the document header. This method is called right after the
      * {@link #startDocument()} method. Extensions sent to this painter between
      * {@link #startDocumentHeader()} and {@link #endDocumentHeader()} apply to the document as
@@ -261,7 +274,4 @@ public interface IFDocumentHandler {
      * @throws IFException if an error occurs while handling this event
      */
     void handleExtensionObject(Object extension) throws IFException;
-
-    //TODO Prototype the following:
-    //ContentHandler handleExtension() throws Exception
 }

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -25,6 +25,7 @@ import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -48,11 +49,13 @@ import org.apache.commons.logging.LogFac
 import org.apache.xmlgraphics.util.QName;
 
 import org.apache.fop.accessibility.AccessibilityEventProducer;
-import org.apache.fop.accessibility.StructureTreeBuilder;
+import org.apache.fop.accessibility.StructureTreeElement;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.fo.ElementMapping;
 import org.apache.fop.fo.ElementMappingRegistry;
 import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.fo.extensions.InternalElementMapping;
 import org.apache.fop.render.intermediate.extensions.DocumentNavigationExtensionConstants;
 import org.apache.fop.render.intermediate.extensions.DocumentNavigationHandler;
 import org.apache.fop.traits.BorderProps;
@@ -62,7 +65,7 @@ import org.apache.fop.util.ContentHandle
 import org.apache.fop.util.ContentHandlerFactoryRegistry;
 import org.apache.fop.util.DOMBuilderContentHandlerFactory;
 import org.apache.fop.util.DefaultErrorListener;
-import org.apache.fop.util.DelegatingContentHandler;
+import org.apache.fop.util.LanguageTags;
 import org.apache.fop.util.XMLUtil;
 
 /**
@@ -153,24 +156,59 @@ public class IFParser implements IFConst
 
         private ContentHandler navParser;
 
-        private StructureTreeBuilder structureTreeBuilder;
-
-        private ContentHandler structureTreeBuilderWrapper;
+        private ContentHandler structureTreeHandler;
 
         private Attributes pageSequenceAttributes;
 
-        private final class StructureTreeBuilderWrapper extends DelegatingContentHandler {
+        private Map<String, StructureTreeElement> structureTreeElements
+                = new HashMap<String, StructureTreeElement>();
 
-            private StructureTreeBuilderWrapper()
-                    throws SAXException {
-                super(structureTreeBuilder.getHandlerForNextPageSequence());
+        private final class StructureTreeHandler extends DefaultHandler {
+
+            private final StructureTreeEventHandler structureTreeEventHandler;
+
+            private StructureTreeHandler(StructureTreeEventHandler structureTreeEventHandler,
+                    Locale pageSequenceLanguage) throws SAXException {
+                this.structureTreeEventHandler = structureTreeEventHandler;
+                structureTreeEventHandler.startPageSequence(pageSequenceLanguage);
             }
 
             public void endDocument() throws SAXException {
-                super.endDocument();
                 startIFElement(EL_PAGE_SEQUENCE, pageSequenceAttributes);
                 pageSequenceAttributes = null;
             }
+
+            @Override
+            public void startElement(String uri, String localName, String qName,
+                    Attributes attributes) throws SAXException {
+                if (!"structure-tree".equals(localName)) {
+                    if (localName.equals("marked-content")) {
+                        localName = "#PCDATA";
+                    }
+                    String structID = attributes.getValue(InternalElementMapping.URI,
+                            InternalElementMapping.STRUCT_ID);
+                    if (structID == null) {
+                        structureTreeEventHandler.startNode(localName, attributes);
+                    } else if (localName.equals("external-graphic")
+                            || localName.equals("instream-foreign-object")) {
+                        StructureTreeElement structureTreeElement
+                                = structureTreeEventHandler.startImageNode(localName, attributes);
+                        structureTreeElements.put(structID, structureTreeElement);
+                    } else {
+                        StructureTreeElement structureTreeElement = structureTreeEventHandler
+                                    .startReferencedNode(localName, attributes);
+                        structureTreeElements.put(structID, structureTreeElement);
+                    }
+                }
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String arqNameg2)
+                    throws SAXException {
+                if (!"structure-tree".equals(localName)) {
+                    structureTreeEventHandler.endNode(localName);
+                }
+            }
         }
 
         public Handler(IFDocumentHandler documentHandler, FOUserAgent userAgent,
@@ -180,6 +218,7 @@ public class IFParser implements IFConst
             this.elementMappingRegistry = elementMappingRegistry;
             elementHandlers.put(EL_DOCUMENT, new DocumentHandler());
             elementHandlers.put(EL_HEADER, new DocumentHeaderHandler());
+            elementHandlers.put(EL_LOCALE, new LocaleHandler());
             elementHandlers.put(EL_TRAILER, new DocumentTrailerHandler());
             elementHandlers.put(EL_PAGE_SEQUENCE, new PageSequenceHandler());
             elementHandlers.put(EL_PAGE, new PageHandler());
@@ -197,11 +236,6 @@ public class IFParser implements IFConst
             elementHandlers.put(EL_LINE, new LineHandler());
             elementHandlers.put(EL_BORDER_RECT, new BorderRectHandler());
             elementHandlers.put(EL_IMAGE, new ImageHandler());
-
-            if (userAgent.isAccessibilityEnabled()) {
-                structureTreeBuilder = new StructureTreeBuilder(tFactory);
-                userAgent.setStructureTree(structureTreeBuilder.getStructureTree());
-            }
         }
 
         private void establishForeignAttributes(Map<QName, String> foreignAttributes) {
@@ -212,14 +246,6 @@ public class IFParser implements IFConst
             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 {
@@ -231,10 +257,13 @@ public class IFParser implements IFConst
                 if (NAMESPACE.equals(uri)) {
                     if (localName.equals(EL_PAGE_SEQUENCE) && userAgent.isAccessibilityEnabled()) {
                         pageSequenceAttributes = new AttributesImpl(attributes);
-                        structureTreeBuilderWrapper = new StructureTreeBuilderWrapper();
+                        Locale language = getLanguage(attributes);
+                        structureTreeHandler = new StructureTreeHandler(
+                                userAgent.getStructureTreeEventHandler(), language);
+
                     } else if (localName.equals(EL_STRUCTURE_TREE)) {
                         if (userAgent.isAccessibilityEnabled()) {
-                            delegate = structureTreeBuilderWrapper;
+                            delegate = structureTreeHandler;
                         } else {
                             /* Delegate to a handler that does nothing */
                             delegate = new DefaultHandler();
@@ -260,7 +289,8 @@ public class IFParser implements IFConst
                 } else if (DocumentNavigationExtensionConstants.NAMESPACE.equals(uri)) {
                     if (this.navParser == null) {
                         this.navParser = new DocumentNavigationHandler(
-                                this.documentHandler.getDocumentNavigationHandler());
+                                this.documentHandler.getDocumentNavigationHandler(),
+                                        structureTreeElements);
                     }
                     delegate = this.navParser;
                     delegateDepth++;
@@ -299,6 +329,11 @@ public class IFParser implements IFConst
             }
         }
 
+        private static Locale getLanguage(Attributes attributes) {
+            String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
+            return (xmllang == null) ? null : LanguageTags.toLocale(xmllang);
+        }
+
         private boolean startIFElement(String localName, Attributes attributes)
                 throws SAXException {
             lastAttributes = new AttributesImpl(attributes);
@@ -413,6 +448,12 @@ public class IFParser implements IFConst
 
         }
 
+        private class LocaleHandler extends AbstractElementHandler {
+            public void startElement(Attributes attributes) throws IFException {
+                documentHandler.setDocumentLocale(getLanguage(attributes));
+            }
+        }
+
         private class DocumentTrailerHandler extends AbstractElementHandler {
 
             public void startElement(Attributes attributes) throws IFException {
@@ -429,10 +470,9 @@ public class IFParser implements IFConst
 
             public void startElement(Attributes attributes) throws IFException {
                 String id = attributes.getValue("id");
-                String xmllang = attributes.getValue(XML_NAMESPACE, "lang");
-                if (xmllang != null) {
-                    documentHandler.getContext().setLanguage(
-                            XMLUtil.convertRFC3066ToLocale(xmllang));
+                Locale language = getLanguage(attributes);
+                if (language != null) {
+                    documentHandler.getContext().setLanguage(language);
                 }
                 Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
                 establishForeignAttributes(foreignAttributes);
@@ -578,9 +618,9 @@ public class IFParser implements IFConst
                 s = lastAttributes.getValue("word-spacing");
                 int wordSpacing = (s != null ? Integer.parseInt(s) : 0);
                 int[] dx = XMLUtil.getAttributeAsIntArray(lastAttributes, "dx");
-                setStructurePointer(lastAttributes);
+                establishStructureTreeElement(lastAttributes);
                 painter.drawText(x, y, letterSpacing, wordSpacing, dx, content.toString());
-                resetStructurePointer();
+                resetStructureTreeElement();
             }
 
             public boolean ignoreCharacters() {
@@ -675,7 +715,7 @@ public class IFParser implements IFConst
                 int height = Integer.parseInt(lastAttributes.getValue("height"));
                 Map<QName, String> foreignAttributes = getForeignAttributes(lastAttributes);
                 establishForeignAttributes(foreignAttributes);
-                setStructurePointer(lastAttributes);
+                establishStructureTreeElement(lastAttributes);
                 if (foreignObject != null) {
                     painter.drawImage(foreignObject,
                             new Rectangle(x, y, width, height));
@@ -689,7 +729,7 @@ public class IFParser implements IFConst
                     painter.drawImage(uri, new Rectangle(x, y, width, height));
                 }
                 resetForeignAttributes();
-                resetStructurePointer();
+                resetStructureTreeElement();
                 inForeignObject = false;
             }
 
@@ -743,13 +783,20 @@ public class IFParser implements IFConst
             return foreignAttributes;
         }
 
-        private void setStructurePointer(Attributes attributes) {
-            String ptr = attributes.getValue("ptr");
-            if (ptr != null && ptr.length() > 0) {
-                establishStructurePointer(ptr);
+        private void establishStructureTreeElement(Attributes attributes) {
+            String structRef = attributes.getValue(InternalElementMapping.URI,
+                    InternalElementMapping.STRUCT_REF);
+            if (structRef != null && structRef.length() > 0) {
+                assert structureTreeElements.containsKey(structRef);
+                StructureTreeElement structureTreeElement = structureTreeElements.get(structRef);
+                documentHandler.getContext().setStructureTreeElement(structureTreeElement);
             }
         }
 
+        private void resetStructureTreeElement() {
+            documentHandler.getContext().resetStructureTreeElement();
+        }
+
         /** {@inheritDoc} */
         public void characters(char[] ch, int start, int length) throws SAXException {
             if (delegate != null) {

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -50,6 +50,7 @@ import org.apache.xmlgraphics.xmp.schema
 import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
 
 import org.apache.fop.Version;
+import org.apache.fop.accessibility.StructureTreeElement;
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.MimeConstants;
@@ -231,7 +232,11 @@ public class IFRenderer extends Abstract
      */
     protected IFDocumentHandler createDefaultDocumentHandler() {
         IFSerializer serializer = new IFSerializer();
-        serializer.setContext(new IFContext(getUserAgent()));
+        FOUserAgent userAgent = getUserAgent();
+        serializer.setContext(new IFContext(userAgent));
+        if (userAgent.isAccessibilityEnabled()) {
+            userAgent.setStructureTreeEventHandler(serializer.getStructureTreeEventHandler());
+        }
         return serializer;
     }
 
@@ -298,6 +303,11 @@ public class IFRenderer extends Abstract
         log.debug("Rendering finished.");
     }
 
+    @Override
+    public void setDocumentLocale(Locale locale) {
+        documentHandler.setDocumentLocale(locale);
+    }
+
     /** {@inheritDoc} */
     public void processOffDocumentItem(OffDocumentItem odi) {
         if (odi instanceof DestinationData) {
@@ -623,12 +633,12 @@ public class IFRenderer extends Abstract
         documentHandler.getContext().resetForeignAttributes();
     }
 
-    private void establishStructurePointer(String ptr) {
-        documentHandler.getContext().setStructurePointer(ptr);
+    private void establishStructureTreeElement(StructureTreeElement structureTreeElement) {
+        documentHandler.getContext().setStructureTreeElement(structureTreeElement);
     }
 
     private void resetStructurePointer() {
-        documentHandler.getContext().resetStructurePointer();
+        documentHandler.getContext().resetStructureTreeElement();
     }
 
     /** {@inheritDoc} */
@@ -845,8 +855,9 @@ public class IFRenderer extends Abstract
 
     /** {@inheritDoc} */
     public void renderInlineViewport(InlineViewport viewport) {
-        String ptr = (String) viewport.getTrait(Trait.PTR);
-        establishStructurePointer(ptr);
+        StructureTreeElement structElem
+                = (StructureTreeElement) viewport.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
+        establishStructureTreeElement(structElem);
         pushdID(viewport);
         Dimension dim = new Dimension(viewport.getIPD(), viewport.getBPD());
         viewportDimensionStack.push(dim);
@@ -906,7 +917,6 @@ public class IFRenderer extends Abstract
         // 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();
@@ -950,7 +960,9 @@ public class IFRenderer extends Abstract
 
         // warn if link trait found but not allowed, else create link
         if (linkTraitFound) {
-            action.setStructurePointer(ptr);  // used for accessibility
+            StructureTreeElement structElem 
+                    = (StructureTreeElement) ip.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
+            action.setStructureTreeElement(structElem);
             Link link = new Link(action, ipRect);
             this.deferredLinks.add(link);
         }
@@ -1003,8 +1015,9 @@ public class IFRenderer extends Abstract
 
         String fontName = getInternalFontNameForArea(text);
         int size = ((Integer) text.getTrait(Trait.FONT_SIZE)).intValue();
-        String ptr = (String)text.getTrait(Trait.PTR); // used for accessibility
-        establishStructurePointer(ptr);
+        StructureTreeElement structElem
+                = (StructureTreeElement) text.getTrait(Trait.STRUCTURE_TREE_ELEMENT);
+        establishStructureTreeElement(structElem);
 
         // This assumes that *all* CIDFonts use a /ToUnicode mapping
         Typeface tf = getTypeface(fontName);

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -31,19 +31,18 @@ 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.accessibility.StructureTreeEventHandler;
+import org.apache.fop.fo.extensions.InternalElementMapping;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.render.PrintRendererConfigurator;
 import org.apache.fop.render.RenderingContext;
+import org.apache.fop.render.intermediate.IFStructureTreeBuilder.IFStructureTreeElement;
 import org.apache.fop.render.intermediate.extensions.AbstractAction;
 import org.apache.fop.render.intermediate.extensions.Bookmark;
 import org.apache.fop.render.intermediate.extensions.BookmarkTree;
@@ -54,9 +53,11 @@ import org.apache.fop.traits.BorderProps
 import org.apache.fop.traits.RuleStyle;
 import org.apache.fop.util.ColorUtil;
 import org.apache.fop.util.DOM2SAX;
+import org.apache.fop.util.LanguageTags;
 import org.apache.fop.util.XMLConstants;
 import org.apache.fop.util.XMLUtil;
 
+
 /**
  * IFPainter implementation that serializes the intermediate format to XML.
  */
@@ -71,11 +72,7 @@ public class IFSerializer extends Abstra
 
     private String currentID = "";
 
-    /**
-     * Default constructor.
-     */
-    public IFSerializer() {
-    }
+    private IFStructureTreeBuilder structureTreeBuilder;
 
     /** {@inheritDoc} */
     @Override
@@ -150,6 +147,14 @@ public class IFSerializer extends Abstra
         }
     }
 
+    @Override
+    public StructureTreeEventHandler getStructureTreeEventHandler() {
+        if (structureTreeBuilder == null) {
+            structureTreeBuilder = new IFStructureTreeBuilder();
+        }
+        return structureTreeBuilder;
+    }
+
     /** {@inheritDoc} */
     @Override
     public void startDocument() throws IFException {
@@ -160,12 +165,27 @@ public class IFSerializer extends Abstra
             handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE);
             handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX,
                     DocumentNavigationExtensionConstants.NAMESPACE);
+            handler.startPrefixMapping(InternalElementMapping.STANDARD_PREFIX,
+                    InternalElementMapping.URI);
             handler.startElement(EL_DOCUMENT);
         } catch (SAXException e) {
             throw new IFException("SAX error in startDocument()", e);
         }
     }
 
+    @Override
+    public void setDocumentLocale(Locale locale) {
+        AttributesImpl atts  = new AttributesImpl();
+        atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA,
+                LanguageTags.toLanguageTag(locale));
+        try {
+            handler.startElement(EL_LOCALE, atts);
+            handler.endElement(EL_LOCALE);
+        } catch (SAXException e) {
+            throw new RuntimeException("Unable to create the " + EL_LOCALE + " element.", e);
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     public void startDocumentHeader() throws IFException {
@@ -227,20 +247,14 @@ public class IFSerializer extends Abstra
             Locale lang = getContext().getLanguage();
             if (lang != null) {
                 atts.addAttribute(XML_NAMESPACE, "lang", "xml:lang", XMLUtil.CDATA,
-                        XMLUtil.toRFC3066(lang));
+                        LanguageTags.toLanguageTag(lang));
             }
             XMLUtil.addAttribute(atts, XMLConstants.XML_SPACE, "preserve");
             addForeignAttributes(atts);
             handler.startElement(EL_PAGE_SEQUENCE, atts);
             if (this.getUserAgent().isAccessibilityEnabled()) {
-                StructureTree structureTree = getUserAgent().getStructureTree();
-                handler.startElement(EL_STRUCTURE_TREE); // add structure tree
-                NodeList nodes = structureTree.getPageSequence(pageSequenceIndex++);
-                for (int i = 0, n = nodes.getLength(); i < n; i++) {
-                    Node node = nodes.item(i);
-                    new DOM2SAX(handler).writeFragment(node);
-                }
-                handler.endElement(EL_STRUCTURE_TREE);
+                assert (structureTreeBuilder != null);
+                structureTreeBuilder.replayEventsForPageSequence(handler, pageSequenceIndex++);
             }
         } catch (SAXException e) {
             throw new IFException("SAX error in startPageSequence()", e);
@@ -250,6 +264,7 @@ public class IFSerializer extends Abstra
     /** {@inheritDoc} */
     public void endPageSequence() throws IFException {
         try {
+
             handler.endElement(EL_PAGE_SEQUENCE);
         } catch (SAXException e) {
             throw new IFException("SAX error in endPageSequence()", e);
@@ -428,7 +443,7 @@ public class IFSerializer extends Abstra
             addAttribute(atts, "width", Integer.toString(rect.width));
             addAttribute(atts, "height", Integer.toString(rect.height));
             addForeignAttributes(atts);
-            addStructurePointerAttribute(atts);
+            addStructureReference(atts);
             handler.element(EL_IMAGE, atts);
         } catch (SAXException e) {
             throw new IFException("SAX error in startGroup()", e);
@@ -456,7 +471,7 @@ public class IFSerializer extends Abstra
             addAttribute(atts, "width", Integer.toString(rect.width));
             addAttribute(atts, "height", Integer.toString(rect.height));
             addForeignAttributes(atts);
-            addStructurePointerAttribute(atts);
+            addStructureReference(atts);
             handler.startElement(EL_IMAGE, atts);
             new DOM2SAX(handler).writeDocument(doc, true);
             handler.endElement(EL_IMAGE);
@@ -571,7 +586,7 @@ public class IFSerializer extends Abstra
             if (dx != null) {
                 addAttribute(atts, "dx", IFUtil.toString(dx));
             }
-            addStructurePointerAttribute(atts);
+            addStructureReference(atts);
             handler.startElement(EL_TEXT, atts);
             char[] chars = text.toCharArray();
             handler.characters(chars, 0, chars.length);
@@ -671,13 +686,22 @@ public class IFSerializer extends Abstra
         XMLUtil.addAttribute(atts, localName, value);
     }
 
-    private void addStructurePointerAttribute(AttributesImpl atts) {
-        String ptr = getContext().getStructurePointer();
-        if (ptr != null) {
-            addAttribute(atts, "ptr", ptr);
+    private void addStructureReference(AttributesImpl atts) {
+        IFStructureTreeElement structureTreeElement
+                = (IFStructureTreeElement) getContext().getStructureTreeElement();
+        if (structureTreeElement != null) {
+            addStructRefAttribute(atts, structureTreeElement.getId());
         }
     }
 
+    private void addStructRefAttribute(AttributesImpl atts, String id) {
+        atts.addAttribute(InternalElementMapping.URI,
+                InternalElementMapping.STRUCT_REF,
+                InternalElementMapping.STANDARD_PREFIX + ":" + InternalElementMapping.STRUCT_REF,
+                XMLConstants.CDATA,
+                id);
+    }
+
     private void addID() throws SAXException {
         String id = getContext().getID();
         if (!currentID.equals(id)) {
@@ -762,7 +786,8 @@ public class IFSerializer extends Abstra
         atts.addAttribute(null, "rect", "rect",
                 XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
         if (getUserAgent().isAccessibilityEnabled()) {
-            addAttribute(atts, "ptr", link.getAction().getStructurePointer());
+            addStructRefAttribute(atts,
+                    ((IFStructureTreeElement) link.getAction().getStructureTreeElement()).getId());
         }
         try {
             handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);
@@ -806,5 +831,4 @@ public class IFSerializer extends Abstra
             throw new IFException("SAX error serializing object", e);
         }
     }
-
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFSerializerMaker.java Fri Feb 10 16:51:08 2012
@@ -31,6 +31,9 @@ public class IFSerializerMaker extends A
     public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
         IFSerializer handler = new IFSerializer();
         handler.setContext(new IFContext(ua));
+        if (ua.isAccessibilityEnabled()) {
+            ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler());
+        }
         return handler;
     }
 

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java?rev=1242848&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/IFStructureTreeBuilder.java Fri Feb 10 16:51:08 2012
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.render.intermediate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.fop.accessibility.StructureTree2SAXEventAdapter;
+import org.apache.fop.accessibility.StructureTreeElement;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
+import org.apache.fop.fo.extensions.InternalElementMapping;
+import org.apache.fop.util.XMLUtil;
+
+/**
+ * Saves structure tree events as SAX events in order to replay them when it's
+ * time to stream the structure tree to the output.
+ */
+final class IFStructureTreeBuilder implements StructureTreeEventHandler {
+
+    static final class IFStructureTreeElement implements StructureTreeElement {
+
+        private final String id;
+
+        IFStructureTreeElement() {
+            this.id = null;
+        }
+
+        IFStructureTreeElement(String id) {
+            this.id = id;
+        }
+
+        public String getId() {
+            return id;
+        }
+    }
+
+    /** A SAX handler that records events to replay them later. */
+    static class SAXEventRecorder extends DefaultHandler {
+
+        private final List<SAXEventRecorder.Event> events = new ArrayList<SAXEventRecorder.Event>();
+
+        private abstract static class Event {
+            abstract void replay(ContentHandler handler) throws SAXException;
+        }
+
+        private abstract static class Element extends SAXEventRecorder.Event {
+
+            protected final String uri;
+            protected final String localName;
+            protected final String qName;
+
+            private Element(String uri, String localName, String qName) {
+                this.uri = uri;
+                this.localName = localName;
+                this.qName = qName;
+            }
+        }
+
+        private static final class StartElement extends SAXEventRecorder.Element {
+
+            private final Attributes attributes;
+
+            private StartElement(String uri, String localName, String qName,
+                    Attributes attributes) {
+                super(uri, localName, qName);
+                this.attributes = attributes;
+            }
+
+            @Override
+            void replay(ContentHandler handler) throws SAXException {
+                handler.startElement(uri, localName, qName, attributes);
+            }
+        }
+
+        private static final class EndElement extends SAXEventRecorder.Element {
+
+            private EndElement(String uri, String localName, String qName) {
+                super(uri, localName, qName);
+            }
+
+            @Override
+            void replay(ContentHandler handler) throws SAXException {
+                handler.endElement(uri, localName, qName);
+            }
+        }
+
+        private static final class StartPrefixMapping extends SAXEventRecorder.Event {
+
+            private final String prefix;
+            private final String uri;
+
+            private StartPrefixMapping(String prefix, String uri) {
+                this.prefix = prefix;
+                this.uri = uri;
+            }
+
+            @Override
+            void replay(ContentHandler handler) throws SAXException {
+                handler.startPrefixMapping(prefix, uri);
+            }
+        }
+
+        private static final class EndPrefixMapping extends SAXEventRecorder.Event {
+
+            private final String prefix;
+
+            private EndPrefixMapping(String prefix) {
+                this.prefix = prefix;
+            }
+
+            @Override
+            void replay(ContentHandler handler) throws SAXException {
+                handler.endPrefixMapping(prefix);
+            }
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName,
+                Attributes attributes) throws SAXException {
+            events.add(new StartElement(uri, localName, qName, attributes));
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) throws SAXException {
+            events.add(new EndElement(uri, localName, qName));
+        }
+
+        @Override
+        public void startPrefixMapping(String prefix, String uri) throws SAXException {
+            events.add(new StartPrefixMapping(prefix, uri));
+        }
+
+        @Override
+        public void endPrefixMapping(String prefix) throws SAXException {
+            events.add(new EndPrefixMapping(prefix));
+        }
+
+        /**
+         * Replays the recorded events.
+         *
+         * @param handler {@code ContentHandler} to replay events on
+         */
+        public void replay(ContentHandler handler) throws SAXException {
+            for (SAXEventRecorder.Event e : events) {
+                e.replay(handler);
+            }
+        }
+    }
+
+    private StructureTreeEventHandler delegate;
+
+    private final List<SAXEventRecorder> pageSequenceEventRecorders
+            = new ArrayList<SAXEventRecorder>();
+
+    private int idCounter;
+
+    /**
+     * Replay SAX events for a page sequence.
+     * @param handler The handler that receives SAX events
+     * @param pageSequenceIndex The index of the page sequence
+     * @throws SAXException
+     */
+    public void replayEventsForPageSequence(ContentHandler handler,
+            int pageSequenceIndex) throws SAXException {
+        pageSequenceEventRecorders.get(pageSequenceIndex).replay(handler);
+    }
+
+    public void startPageSequence(Locale locale) {
+        SAXEventRecorder eventRecorder = new SAXEventRecorder();
+        pageSequenceEventRecorders.add(eventRecorder);
+        delegate = StructureTree2SAXEventAdapter.newInstance(eventRecorder);
+        delegate.startPageSequence(locale);
+    }
+
+    public void endPageSequence() {
+         delegate.endPageSequence();
+    }
+
+    public StructureTreeElement startNode(String name, Attributes attributes) {
+        delegate.startNode(name, attributes);
+        return new IFStructureTreeElement();
+    }
+
+    public void endNode(String name) {
+        delegate.endNode(name);
+    }
+
+    public StructureTreeElement startImageNode(String name, Attributes attributes) {
+        String id = getNextID();
+        AttributesImpl atts = addIDAttribute(attributes, id);
+        delegate.startImageNode(name, atts);
+        return new IFStructureTreeElement(id);
+    }
+
+    public StructureTreeElement startReferencedNode(String name, Attributes attributes) {
+        String id = getNextID();
+        AttributesImpl atts = addIDAttribute(attributes, id);
+        delegate.startReferencedNode(name, atts);
+        return new IFStructureTreeElement(id);
+    }
+
+    private String getNextID() {
+        return Integer.toHexString(idCounter++);
+    }
+
+    private AttributesImpl addIDAttribute(Attributes attributes, String id) {
+        AttributesImpl atts = new AttributesImpl(attributes);
+        atts.addAttribute(InternalElementMapping.URI,
+                InternalElementMapping.STRUCT_ID,
+                InternalElementMapping.STANDARD_PREFIX + ":" + InternalElementMapping.STRUCT_ID,
+                XMLUtil.CDATA,
+                id);
+        return atts;
+    }
+}

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -21,13 +21,15 @@ package org.apache.fop.render.intermedia
 
 import org.apache.xmlgraphics.util.XMLizable;
 
+import org.apache.fop.accessibility.StructureTreeElement;
+
 /**
  * Abstract base class for document actions, like "go-to" actions with absolute page coordinates.
  */
 public abstract class AbstractAction implements XMLizable {
 
     private String id;
-    private String structurePointer;
+    private StructureTreeElement structureTreeElement;
 
     /**
      * Sets an ID to make the action referencable.
@@ -47,18 +49,18 @@ public abstract class AbstractAction imp
 
     /**
      * Sets the structure element corresponding to this action.
-     * @param structurePointer a reference to the structure element
+     * @param structureTreeElement a reference to the structure element
      */
-    public void setStructurePointer(String structurePointer) {
-        this.structurePointer = structurePointer;
+    public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
+        this.structureTreeElement = structureTreeElement;
     }
 
     /**
      * Returns the structure element corresponding to this action.
      * @return the reference to the structure element
      */
-    public String getStructurePointer() {
-        return structurePointer;
+    public StructureTreeElement getStructureTreeElement() {
+        return structureTreeElement;
     }
 
     /**

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -21,6 +21,7 @@ package org.apache.fop.render.intermedia
 
 import java.awt.Point;
 import java.awt.Rectangle;
+import java.util.Map;
 import java.util.Stack;
 
 import org.xml.sax.Attributes;
@@ -30,6 +31,8 @@ import org.xml.sax.helpers.DefaultHandle
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import org.apache.fop.accessibility.StructureTreeElement;
+import org.apache.fop.fo.extensions.InternalElementMapping;
 import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
 import org.apache.fop.render.intermediate.IFException;
 import org.apache.fop.util.XMLUtil;
@@ -48,14 +51,20 @@ public class DocumentNavigationHandler e
 
     private IFDocumentNavigationHandler navHandler;
 
-    private String structurePointer;
+    private StructureTreeElement structureTreeElement;
+
+    private Map<String, StructureTreeElement> structureTreeElements;
 
     /**
      * Main constructor.
      * @param navHandler the navigation handler that will receive the events
+     * @param structureTreeElements the elements representing the structure of the document
      */
-    public DocumentNavigationHandler(IFDocumentNavigationHandler navHandler) {
+    public DocumentNavigationHandler(IFDocumentNavigationHandler navHandler,
+            Map<String, StructureTreeElement> structureTreeElements) {
         this.navHandler = navHandler;
+        assert structureTreeElements != null;
+        this.structureTreeElements = structureTreeElements;
     }
 
     /** {@inheritDoc} */
@@ -98,7 +107,8 @@ public class DocumentNavigationHandler e
                     throw new SAXException(localName + " must be the root element!");
                 }
                 Rectangle targetRect = XMLUtil.getAttributeAsRectangle(attributes, "rect");
-                structurePointer = attributes.getValue("ptr");
+                structureTreeElement = structureTreeElements.get(attributes.getValue(
+                        InternalElementMapping.URI, InternalElementMapping.STRUCT_REF));
                 Link link = new Link(null, targetRect);
                 objectStack.push(link);
             } else if (GOTO_XY.getLocalName().equals(localName)) {
@@ -121,8 +131,8 @@ public class DocumentNavigationHandler e
                     }
                     action = new GoToXYAction(id, pageIndex, location);
                 }
-                if (structurePointer != null) {
-                    action.setStructurePointer(structurePointer);
+                if (structureTreeElement != null) {
+                    action.setStructureTreeElement(structureTreeElement);
                 }
                 objectStack.push(action);
             } else if (GOTO_URI.getLocalName().equals(localName)) {
@@ -134,8 +144,8 @@ public class DocumentNavigationHandler e
                 if (id != null) {
                     action.setID(id);
                 }
-                if (structurePointer != null) {
-                    action.setStructurePointer(structurePointer);
+                if (structureTreeElement != null) {
+                    action.setStructureTreeElement(structureTreeElement);
                 }
                 objectStack.push(action);
             } else {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/intermediate/util/IFDocumentHandlerProxy.java Fri Feb 10 16:51:08 2012
@@ -20,9 +20,12 @@
 package org.apache.fop.render.intermediate.util;
 
 import java.awt.Dimension;
+import java.util.Locale;
 
 import javax.xml.transform.Result;
 
+import org.apache.fop.accessibility.DummyStructureTreeEventHandler;
+import org.apache.fop.accessibility.StructureTreeEventHandler;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.render.intermediate.IFContext;
 import org.apache.fop.render.intermediate.IFDocumentHandler;
@@ -94,6 +97,11 @@ public class IFDocumentHandlerProxy impl
     }
 
     /** {@inheritDoc} */
+    public StructureTreeEventHandler getStructureTreeEventHandler() {
+        return DummyStructureTreeEventHandler.INSTANCE;
+    }
+
+    /** {@inheritDoc} */
     public void setResult(Result result) throws IFException {
         this.delegate.setResult(result);
     }
@@ -104,6 +112,12 @@ public class IFDocumentHandlerProxy impl
     }
 
     /** {@inheritDoc} */
+    public void setDocumentLocale(Locale locale) {
+         this.delegate.setDocumentLocale(locale);
+
+    }
+
+    /** {@inheritDoc} */
     public void startDocumentHeader() throws IFException {
         this.delegate.startDocumentHeader();
     }
@@ -184,4 +198,4 @@ public class IFDocumentHandlerProxy impl
         this.delegate.handleExtensionObject(extension);
     }
 
-}
\ No newline at end of file
+}

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/FOToPDFRoleMap.java Fri Feb 10 16:51:08 2012
@@ -22,8 +22,6 @@ package org.apache.fop.render.pdf;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.w3c.dom.Node;
-
 import org.apache.fop.events.EventBroadcaster;
 import org.apache.fop.pdf.PDFName;
 import org.apache.fop.pdf.PDFObject;
@@ -37,9 +35,11 @@ final class FOToPDFRoleMap {
     /**
      * Standard structure types defined by the PDF Reference, Fourth Edition (PDF 1.5).
      */
-    private static final Map STANDARD_STRUCTURE_TYPES = new HashMap();
+    private static final Map<String, PDFName> STANDARD_STRUCTURE_TYPES
+            = new HashMap<String, PDFName>();
 
-    private static final Map DEFAULT_MAPPINGS = new java.util.HashMap();
+    private static final Map<String, Mapper> DEFAULT_MAPPINGS
+            = new java.util.HashMap<String, Mapper>();
 
     private static final PDFName THEAD;
     private static final PDFName NON_STRUCT;
@@ -172,7 +172,7 @@ final class FOToPDFRoleMap {
      * @return the structure type or null if no match could be found
      */
     public static PDFName mapFormattingObject(String fo, PDFObject parent) {
-        Mapper mapper = (Mapper)DEFAULT_MAPPINGS.get(fo);
+        Mapper mapper = (Mapper) DEFAULT_MAPPINGS.get(fo);
         if (mapper != null) {
             return mapper.getStructureType(parent);
         } else {
@@ -180,27 +180,32 @@ final class FOToPDFRoleMap {
         }
     }
 
-    public static PDFName mapFormattingObject(Node fo, PDFObject parent,
-            EventBroadcaster eventBroadcaster) {
+    /**
+     * Maps a Formatting Object to a PDFName representing the associated structure type.
+     * @param fo the formatting object's local name
+     * @param role the value of the formatting object's role property
+     * @param parent the parent of the structure element to be mapped
+     * @param eventBroadcaster the event broadcaster
+     * @return the structure type or null if no match could be found
+     */
+    public static PDFName mapFormattingObject(String fo, String role,
+            PDFObject parent, EventBroadcaster eventBroadcaster) {
         PDFName type = null;
-        Node role = fo.getAttributes().getNamedItemNS(null, "role");
         if (role == null) {
-            type = mapFormattingObject(fo.getLocalName(), parent);
+            type = mapFormattingObject(fo, parent);
         } else {
-            String customType = role.getNodeValue();
-            type = (PDFName) STANDARD_STRUCTURE_TYPES.get(customType);
+            type = (PDFName) STANDARD_STRUCTURE_TYPES.get(role);
             if (type == null) {
-                String foName = fo.getLocalName();
-                type = mapFormattingObject(foName, parent);
+                type = mapFormattingObject(fo, parent);
                 PDFEventProducer.Provider.get(eventBroadcaster).nonStandardStructureType(fo,
-                        foName, customType, type.toString().substring(1));
+                        fo, role, type.toString().substring(1));
             }
         }
         assert type != null;
         return type;
     }
 
-    private static interface Mapper {
+    private interface Mapper {
         PDFName getStructureType(PDFObject parent);
     }
 
@@ -222,7 +227,7 @@ final class FOToPDFRoleMap {
 
         public PDFName getStructureType(PDFObject parent) {
             PDFStructElem grandParent = (PDFStructElem)
-                ((PDFStructElem)parent).getParentStructElem();
+                ((PDFStructElem) parent).getParentStructElem();
             //TODO What to do with cells from table-footer? Currently they are mapped on TD.
             PDFName type;
             if (THEAD.equals(grandParent.getStructureType())) {

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -25,15 +25,16 @@ import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
-import org.w3c.dom.NodeList;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import org.apache.xmlgraphics.xmp.Metadata;
 
+import org.apache.fop.accessibility.StructureTreeEventHandler;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.fo.extensions.xmp.XMPMetadata;
 import org.apache.fop.pdf.PDFAnnotList;
@@ -45,28 +46,26 @@ import org.apache.fop.render.extensions.
 import org.apache.fop.render.extensions.prepress.PageScale;
 import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
 import org.apache.fop.render.intermediate.IFContext;
-import org.apache.fop.render.intermediate.IFDocumentHandler;
 import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
 import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
 import org.apache.fop.render.intermediate.IFException;
 import org.apache.fop.render.intermediate.IFPainter;
 import org.apache.fop.render.pdf.extensions.PDFEmbeddedFileExtensionAttachment;
-import org.apache.fop.util.XMLUtil;
 
 /**
- * {@link IFDocumentHandler} implementation that produces PDF.
+ * {@link org.apache.fop.render.intermediate.IFDocumentHandler} implementation that produces PDF.
  */
 public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
 
     /** logging instance */
     private static Log log = LogFactory.getLog(PDFDocumentHandler.class);
 
-    private int pageSequenceIndex;
-
     private boolean accessEnabled;
 
     private PDFLogicalStructureHandler logicalStructureHandler;
 
+    private PDFStructureTreeBuilder structureTreeBuilder;
+
     /** the PDF Document being created */
     protected PDFDocument pdfDoc;
 
@@ -92,8 +91,7 @@ public class PDFDocumentHandler extends 
     protected PageReference currentPageRef;
 
     /** Used for bookmarks/outlines. */
-    protected Map<Integer, PageReference> pageReferences
-        = new java.util.HashMap<Integer, PageReference>();
+    protected Map<Integer, PageReference> pageReferences = new HashMap<Integer, PageReference>();
 
     private final PDFDocumentNavigationHandler documentNavigationHandler
             = new PDFDocumentNavigationHandler(this);
@@ -145,15 +143,23 @@ public class PDFDocumentHandler extends 
             this.pdfDoc = pdfUtil.setupPDFDocument(this.outputStream);
             this.accessEnabled = getUserAgent().isAccessibilityEnabled();
             if (accessEnabled) {
-                pdfDoc.getRoot().makeTagged();
-                logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc,
-                        getUserAgent().getEventBroadcaster());
+                setupAccessibility();
             }
         } catch (IOException e) {
             throw new IFException("I/O error in startDocument()", e);
         }
     }
 
+    private void setupAccessibility() {
+        pdfDoc.getRoot().makeTagged();
+        logicalStructureHandler = new PDFLogicalStructureHandler(pdfDoc);
+        // TODO this is ugly. All the necessary information should be available
+        // at creation time in order to enforce immutability
+        structureTreeBuilder.setPdfFactory(pdfDoc.getFactory());
+        structureTreeBuilder.setLogicalStructureHandler(logicalStructureHandler);
+        structureTreeBuilder.setEventBroadcaster(getUserAgent().getEventBroadcaster());
+    }
+
     /** {@inheritDoc} */
     public void endDocumentHeader() throws IFException {
         pdfUtil.generateDefaultXMPMetadata();
@@ -178,18 +184,7 @@ public class PDFDocumentHandler extends 
 
     /** {@inheritDoc} */
     public void startPageSequence(String id) throws IFException {
-        //TODO page sequence title
-
-        if (this.pdfDoc.getRoot().getLanguage() == null
-                && getContext().getLanguage() != null) {
-            //No document-level language set, so we use the first page-sequence's language
-            this.pdfDoc.getRoot().setLanguage(XMLUtil.toRFC3066(getContext().getLanguage()));
-        }
-
-        if (accessEnabled) {
-            NodeList nodes = getUserAgent().getStructureTree().getPageSequence(pageSequenceIndex++);
-            logicalStructureHandler.processStructureTree(nodes, getContext().getLanguage());
-        }
+        //nop
     }
 
     /** {@inheritDoc} */
@@ -289,9 +284,9 @@ public class PDFDocumentHandler extends 
     /** {@inheritDoc} */
     public void handleExtensionObject(Object extension) throws IFException {
         if (extension instanceof XMPMetadata) {
-            pdfUtil.renderXMPMetadata((XMPMetadata)extension);
+            pdfUtil.renderXMPMetadata((XMPMetadata) extension);
         } else if (extension instanceof Metadata) {
-            XMPMetadata wrapper = new XMPMetadata(((Metadata)extension));
+            XMPMetadata wrapper = new XMPMetadata(((Metadata) extension));
             pdfUtil.renderXMPMetadata(wrapper);
         } else if (extension instanceof PDFEmbeddedFileExtensionAttachment) {
             PDFEmbeddedFileExtensionAttachment embeddedFile
@@ -307,6 +302,11 @@ public class PDFDocumentHandler extends 
         }
     }
 
+    /** {@inheritDoc} */
+    public void setDocumentLocale(Locale locale) {
+        pdfDoc.getRoot().setLanguage(locale);
+    }
+
     PageReference getPageReference(int pageIndex) {
         return this.pageReferences.get(Integer.valueOf(pageIndex));
     }
@@ -332,4 +332,11 @@ public class PDFDocumentHandler extends 
         }
     }
 
+    @Override
+    public StructureTreeEventHandler getStructureTreeEventHandler() {
+        if (structureTreeBuilder == null) {
+            structureTreeBuilder = new PDFStructureTreeBuilder();
+        }
+        return structureTreeBuilder;
+    }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFDocumentHandlerMaker.java Fri Feb 10 16:51:08 2012
@@ -36,6 +36,9 @@ public class PDFDocumentHandlerMaker ext
     public IFDocumentHandler makeIFDocumentHandler(FOUserAgent ua) {
         PDFDocumentHandler handler = new PDFDocumentHandler();
         handler.setContext(new IFContext(ua));
+        if (ua.isAccessibilityEnabled()) {
+            ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler());
+        }
         return handler;
     }
 

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=1242848&r1=1242847&r2=1242848&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 Fri Feb 10 16:51:08 2012
@@ -31,6 +31,7 @@ import org.apache.fop.pdf.PDFFactory;
 import org.apache.fop.pdf.PDFGoTo;
 import org.apache.fop.pdf.PDFLink;
 import org.apache.fop.pdf.PDFOutline;
+import org.apache.fop.pdf.PDFStructElem;
 import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
 import org.apache.fop.render.intermediate.IFException;
 import org.apache.fop.render.intermediate.extensions.AbstractAction;
@@ -111,10 +112,9 @@ public class PDFDocumentNavigationHandle
         PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
                 targetRect2D, pdfAction);
         if (pdfLink != null) {
-            String ptr = link.getAction().getStructurePointer();
-            if (documentHandler.getUserAgent().isAccessibilityEnabled()
-                    && ptr != null && ptr.length() > 0) {
-                documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, ptr);
+            PDFStructElem structure = (PDFStructElem) link.getAction().getStructureTreeElement();
+            if (documentHandler.getUserAgent().isAccessibilityEnabled() && structure != null) {
+                documentHandler.getLogicalStructureHandler().addLinkContentItem(pdfLink, structure);
             }
             documentHandler.currentPage.addAnnotation(pdfLink);
         }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java?rev=1242848&r1=1242847&r2=1242848&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFLogicalStructureHandler.java Fri Feb 10 16:51:08 2012
@@ -19,16 +19,8 @@
 
 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.events.EventBroadcaster;
-import org.apache.fop.fo.extensions.ExtensionElementMapping;
-import org.apache.fop.fo.extensions.InternalElementMapping;
 import org.apache.fop.pdf.PDFArray;
 import org.apache.fop.pdf.PDFDictionary;
 import org.apache.fop.pdf.PDFDocument;
@@ -53,13 +45,6 @@ class PDFLogicalStructureHandler {
 
     private final PDFDocument pdfDoc;
 
-    private final EventBroadcaster eventBroadcaster;
-
-    /**
-     * Map of references to the corresponding structure elements.
-     */
-    private final Map structTreeMap = new HashMap();
-
     private final PDFParentTree parentTree = new PDFParentTree();
 
     private int parentTreeKey;
@@ -108,23 +93,16 @@ class PDFLogicalStructureHandler {
      *
      * @param pdfDoc a document
      */
-    PDFLogicalStructureHandler(PDFDocument pdfDoc, EventBroadcaster eventBroadcaster) {
+    PDFLogicalStructureHandler(PDFDocument pdfDoc) {
         this.pdfDoc = pdfDoc;
-        this.eventBroadcaster = eventBroadcaster;
         PDFStructTreeRoot structTreeRoot = pdfDoc.getFactory().makeStructTreeRoot(parentTree);
         rootStructureElement = pdfDoc.getFactory().makeStructureElement(
                 FOToPDFRoleMap.mapFormattingObject("root", structTreeRoot), structTreeRoot);
         structTreeRoot.addKid(rootStructureElement);
     }
 
-    /**
-     * Converts the given structure tree into PDF.
-     *
-     * @param structureTree the structure tree of the current page sequence
-     * @param language language set on the page sequence
-     */
-    void processStructureTree(NodeList structureTree, Locale language) {
-        pdfDoc.enforceLanguageOnRoot();
+
+    PDFStructElem createPageSequence(Locale language) {
         PDFStructElem structElemPart = pdfDoc.getFactory().makeStructureElement(
                 FOToPDFRoleMap.mapFormattingObject("page-sequence", rootStructureElement),
                 rootStructureElement);
@@ -132,49 +110,7 @@ class PDFLogicalStructureHandler {
         if (language != null) {
             structElemPart.setLanguage(language);
         }
-
-        for (int i = 0, n = structureTree.getLength(); i < n; i++) {
-            Node node = structureTree.item(i);
-            assert node.getLocalName().equals("flow")
-                    || node.getLocalName().equals("static-content");
-            PDFStructElem structElemSect = pdfDoc.getFactory().makeStructureElement(
-                    FOToPDFRoleMap.mapFormattingObject(node.getLocalName(), structElemPart),
-                    structElemPart);
-            structElemPart.addKid(structElemSect);
-            NodeList childNodes = node.getChildNodes();
-            for (int j = 0, m = childNodes.getLength(); j < m; j++) {
-                processNode(childNodes.item(j), structElemSect, true);
-            }
-        }
-    }
-
-    private void processNode(Node node, PDFStructElem parent, boolean addKid) {
-        Node attr = node.getAttributes().getNamedItemNS(InternalElementMapping.URI, "ptr");
-        assert attr != null;
-        String ptr = attr.getNodeValue();
-        PDFStructElem structElem = pdfDoc.getFactory().makeStructureElement(
-                FOToPDFRoleMap.mapFormattingObject(node, parent, eventBroadcaster), parent);
-        // TODO necessary? If a page-sequence is empty (e.g., contains a single
-        // empty fo:block), should the block still be added to the structure
-        // tree? This is not being done for descendant empty elements...
-        if (addKid) {
-            parent.addKid(structElem);
-        }
-        String nodeName = node.getLocalName();
-        if (nodeName.equals("external-graphic") || nodeName.equals("instream-foreign-object")) {
-            Node altTextNode = node.getAttributes().getNamedItemNS(
-                    ExtensionElementMapping.URI, "alt-text");
-            if (altTextNode != null) {
-                structElem.put("Alt", altTextNode.getNodeValue());
-            } else {
-                structElem.put("Alt", "No alternate text specified");
-            }
-        }
-        structTreeMap.put(ptr, structElem);
-        NodeList nodes = node.getChildNodes();
-        for (int i = 0, n = nodes.getLength(); i < n; i++) {
-            processNode(nodes.item(i), structElem, false);
-        }
+        return structElemPart;
     }
 
     private int getNextParentTreeKey() {
@@ -208,96 +144,79 @@ class PDFLogicalStructureHandler {
         parentTree.getNums().put(currentPage.getStructParents(), pageParentTreeArray);
     }
 
-    private MarkedContentInfo addToParentTree(String structurePointer) {
-        PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
-        if (parent == null) {
-            return ARTIFACT;
-        } else {
-            pageParentTreeArray.add(parent);
-            String type = parent.getStructureType().toString();
-            int mcid = pageParentTreeArray.length() - 1;
-            return new MarkedContentInfo(type, mcid, parent);
-        }
+    private MarkedContentInfo addToParentTree(PDFStructElem structureTreeElement) {
+        PDFStructElem parent = (structureTreeElement instanceof PDFStructElem.Placeholder)
+                ? structureTreeElement.getParentStructElem()
+                : structureTreeElement;
+        pageParentTreeArray.add(parent);
+        String type = parent.getStructureType().toString();
+        int mcid = pageParentTreeArray.length() - 1;
+        return new MarkedContentInfo(type, mcid, structureTreeElement);
     }
 
     /**
      * Adds a content item corresponding to text into the structure tree, if
      * there is a structure element associated to it.
      *
-     * @param structurePointer reference to the parent structure element of the
-     * piece of text
+     * @param structElem the parent structure element of the piece of text
      * @return the necessary information for bracketing the content as a
      * marked-content sequence. If there is no element in the structure tree
      * associated to that content, returns an instance whose
      * {@link MarkedContentInfo#tag} value is <code>null</code>. The content
      * must then be treated as an artifact.
      */
-    MarkedContentInfo addTextContentItem(String structurePointer) {
-        MarkedContentInfo mci = addToParentTree(structurePointer);
-        if (mci != ARTIFACT) {
+    MarkedContentInfo addTextContentItem(PDFStructElem structElem) {
+        if (structElem == null) {
+            return ARTIFACT;
+        } else {
+            MarkedContentInfo mci = addToParentTree(structElem);
             PDFDictionary contentItem = new PDFDictionary();
             contentItem.put("Type", MCR);
             contentItem.put("Pg", this.currentPage);
             contentItem.put("MCID", mci.mcid);
             mci.parent.addKid(contentItem);
+            return mci;
         }
-        return mci;
     }
 
     /**
      * Adds a content item corresponding to an image into the structure tree, if
      * there is a structure element associated to it.
      *
-     * @param structurePointer reference to the parent structure element of the
-     * image
+     * @param structElem the parent structure element of the image
      * @return the necessary information for bracketing the content as a
      * marked-content sequence. If there is no element in the structure tree
      * associated to that image, returns an instance whose
-     * {@link MarkedContentInfo#tag} value is <code>null</code>. The image
-     * must then be treated as an artifact.
+     * {@link MarkedContentInfo#tag} value is <code>null</code>. The image must
+     * then be treated as an artifact.
      */
-    MarkedContentInfo addImageContentItem(String structurePointer) {
-        MarkedContentInfo mci = addToParentTree(structurePointer);
-        if (mci != ARTIFACT) {
+    MarkedContentInfo addImageContentItem(PDFStructElem structElem) {
+        if (structElem == null) {
+            return ARTIFACT;
+        } else {
+            MarkedContentInfo mci = addToParentTree(structElem);
             mci.parent.setMCIDKid(mci.mcid);
             mci.parent.setPage(this.currentPage);
+            return mci;
         }
-        return mci;
     }
 
-    // While the PDF spec allows images to be referred as PDF objects, this
-    // makes the Acrobat Pro checker complain that the image is not accessible.
-    // Its alt-text is still read aloud though. Using marked-content sequences
-    // like for text works.
-//    MarkedContentInfo addImageObject(String parentReference) {
-//        MarkedContentInfo mci = addToParentTree(parentReference);
-//        if (mci != ARTIFACT) {
-//            PDFDictionary contentItem = new PDFDictionary();
-//            contentItem.put("Type", OBJR);
-//            contentItem.put("Pg", this.currentPage);
-//            contentItem.put("Obj", null);
-//            mci.parent.addKid(contentItem);
-//        }
-//        return mci;
-//    }
-
     /**
      * Adds a content item corresponding to the given link into the structure
      * tree.
      *
      * @param link a link
-     * @param structurePointer reference to the corresponding parent structure element
+     * @param structureTreeElement its parent structure element
      */
-    void addLinkContentItem(PDFLink link, String structurePointer) {
+    void addLinkContentItem(PDFLink link, PDFStructElem structureTreeElement) {
         int structParent = getNextParentTreeKey();
         link.setStructParent(structParent);
         PDFDictionary contentItem = new PDFDictionary();
         contentItem.put("Type", OBJR);
         contentItem.put("Pg", this.currentPage);
         contentItem.put("Obj", link);
-        PDFStructElem parent = (PDFStructElem) structTreeMap.get(structurePointer);
-        parentTree.getNums().put(structParent, parent);
-        parent.addKid(contentItem);
+        parentTree.getNums().put(structParent, structureTreeElement);
+        structureTreeElement.addKid(contentItem);
     }
 
 }



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