Index: src/java/META-INF/services/org.apache.fop.fo.ElementMapping
===================================================================
--- src/java/META-INF/services/org.apache.fop.fo.ElementMapping	(revision 676141)
+++ src/java/META-INF/services/org.apache.fop.fo.ElementMapping	(working copy)
@@ -1,4 +1,5 @@
 org.apache.fop.fo.FOElementMapping
+org.apache.fop.fo.extensions.pdf.PDFExtensionElementMapping
 org.apache.fop.fo.extensions.svg.SVGElementMapping
 org.apache.fop.fo.extensions.svg.BatikExtensionElementMapping
 org.apache.fop.fo.extensions.ExtensionElementMapping
Index: src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java	(revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java	(revision 0)
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $Id$ */
+package org.apache.fop.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionObj;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.FONode;
+
+public abstract class AbstractPDFExtension extends ExtensionObj {
+
+    /**
+     * Create a new AbstractPDFExtension that is a child of the given
+     * {@link FONode}
+     * 
+     * @param parent    the parent {@link FONode}
+     */
+    public AbstractPDFExtension(FONode parent) {
+        super(parent);
+    }
+
+    /** {@inheritDoc} */
+    public ExtensionAttachment getExtensionAttachment() {
+        return new PDFExtensionAttachment(this);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return  {@link PDFExtensionElementMapping#URI}
+     */
+    public String getNamespaceURI() {
+        return PDFExtensionElementMapping.URI;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return  {@link PDFExtensionElementMapping#PREFIX}
+     */
+    public String getNormalNamespacePrefix() {
+        return PDFExtensionElementMapping.PREFIX;
+    }
+
+}

Property changes on: src/java/org/apache/fop/fo/extensions/pdf/AbstractPDFExtension.java
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/java/org/apache/fop/fo/extensions/pdf/PDFDictionaryExtension.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/pdf/PDFDictionaryExtension.java	(revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFDictionaryExtension.java	(revision 0)
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo.extensions.pdf;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.extensions.ExtensionObj;
+import org.apache.fop.apps.FOPException;
+import org.apache.xmlgraphics.util.QName;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+import java.nio.CharBuffer;
+import java.util.ListIterator;
+
+/**
+ * Class modelling the pdf:dictionary extension object.
+ *
+ * This extension, in co-operation with {@link PDFEntryExtension} allows 
+ * the user to build dictionaries that will be injected into the 
+ * PDF document.
+ * If the type is specified as "catalog", the entries will be added to
+ * the document catalog.
+ */
+public class PDFDictionaryExtension extends AbstractPDFExtension {
+
+    public static final int TYPE_CATALOG = 0;
+    public static final int TYPE_NORMAL = 1;
+    
+    static final String[] TYPES = { "catalog", "normal" };
+    
+    private int type;
+    private String name;
+
+    /**
+     * Create a new PDFDictionaryExtension instance that is
+     * a child of the given {@link FONode}.
+     *
+     * @param parent the parent {@link FONode}
+     */
+    public PDFDictionaryExtension(FONode parent) {
+        super(parent);
+    }
+
+    private static int getType(String typeString) {
+        for (int i = TYPES.length; --i >= 0;) {
+            if (TYPES[i].equals(typeString)) {
+                return i;
+            }
+        }
+        assert false;
+        return -1;
+    }
+    
+    /** {@inheritDoc} */
+    public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException {
+        String dictType = attlist.getValue("type");
+        if (dictType == null || "".equals(dictType)) {
+            //assume "normal" if absent
+            dictType = TYPES[TYPE_NORMAL];
+        }
+        this.type = getType(dictType);
+        this.name = attlist.getValue("name");
+    }
+
+    /** {@inheritDoc} */
+    protected void validateChildNode(Locator loc, String namespaceURI, String localName) throws ValidationException {
+        if (PDFExtensionElementMapping.URI.equals(namespaceURI)) {
+            if ("entry".equals(localName) || "dictionary".equals(localName)) {
+                return; //no problem
+            }
+        }
+        //TODO: Replace by extension-specific event (?)
+        this.invalidChildError(loc, namespaceURI, localName);
+    }
+
+    /**
+     * Return an <code>int</code> identifying the type of PDF dictionary.
+     *
+     * @return  one of {@link #TYPE_CATALOG}, or {@link #TYPE_NORMAL}
+     */
+    public int getType() {
+        return this.type;
+    }
+
+    /**
+     * Return a <code>java.lang.String</code> naming the type of PDF dictionary.
+     * 
+     * @return one of "catalog" or "normal"
+     */
+    public String getTypeName() {
+        return TYPES[this.type];
+    }
+
+    /**
+     * Return the name of this dictionary
+     * 
+     * @return the name of the dictionary
+     */
+    public String getName() {
+        return this.name;
+    }
+    
+    /** {@inheritDoc} */
+    public String getLocalName() {
+        return "dictionary";
+    }
+    
+}
Index: src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java	(revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java	(revision 0)
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $Id$ */
+package org.apache.fop.fo.extensions.pdf;
+
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.PropertyList;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.apps.FOPException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+
+import java.nio.CharBuffer;
+
+/**
+ * Class modelling the <code>pdf:entry</code> extension object.
+ * This extension can be used to create PDF entries in a
+ * <code>pdf:dictionary</code> object.
+ * The object is mapped virtually one-on-one to PDF.
+ * <br/><br/>
+ * <code>&lt;pdf:entry name="PageMode">FullScreen&lt;/pdf:entry></code>
+ * <br/><br/>
+ * will result in "/PageMode FullScreen" being added as an entry
+ * to the dictionary.
+ */
+public class PDFEntryExtension extends AbstractPDFExtension {
+
+    private String entryName;
+    private CharBuffer entryValue;
+    
+    /**
+     * Construct a new PDFEntryExtension instance that is a child
+     * of the given {@link org.apache.fop.fo.FONode}
+     * 
+     * @param parent    the parent {@link org.apache.fop.fo.FONode}
+     */
+    public PDFEntryExtension(FONode parent) {
+        super(parent);
+    }
+    
+    /** {@inheritDoc} */
+    protected void validateChildNode(Locator loc, String namespaceURI, String localName) throws ValidationException {
+        //TODO: Replace by extension-specific event (?)
+        this.invalidChildError(loc, namespaceURI, localName);
+    }
+
+    /** {@inheritDoc} */
+    public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException {
+        this.entryName = attlist.getValue("name");
+        if (this.entryName == null || "".equals(this.entryName)) {
+            this.missingPropertyError("name");
+        }
+        super.processNode(elementName, locator, attlist, pList);
+    }
+
+    /** {@inheritDoc} */
+    protected void addCharacters(char[] data, int start, int length, PropertyList pList, Locator locator) throws FOPException {
+        if (this.entryValue == null) {
+            this.entryValue = CharBuffer.allocate(length);
+        } else {
+            CharBuffer newExpr = CharBuffer.allocate(
+                                    this.entryValue.length() + length);
+            this.entryValue.position(0);
+            newExpr.put(this.entryValue);
+            this.entryValue = newExpr;
+        }
+        this.entryValue.put(data, start, length);
+    }
+
+    /**
+     * Return the name of the PDF entry.
+     * 
+     * @return the name of the entry
+     */
+    public String getEntryName() {
+        return this.entryName;
+    }
+
+    /**
+     * Return the value of the PDF entry (= the #PCDATA 
+     * content of the node in the source document)
+     * 
+     * @return the value of the entry
+     */
+    public String getEntryValue() {
+        this.entryValue.rewind();
+        return this.entryValue.toString();
+    }
+    
+    /** {@inheritDoc} */
+    public String getLocalName() {
+        return "entry";
+    }
+    
+}

Property changes on: src/java/org/apache/fop/fo/extensions/pdf/PDFEntryExtension.java
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java	(revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java	(revision 0)
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $Id$ */
+package org.apache.fop.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+
+import java.io.Serializable;
+
+public class PDFExtensionAttachment implements ExtensionAttachment, Serializable {
+
+    private AbstractPDFExtension ext;
+    
+    public PDFExtensionAttachment() {
+        //nop
+    }
+    
+    public PDFExtensionAttachment(AbstractPDFExtension ext) {
+        this.ext = ext;
+    }
+    
+    public AbstractPDFExtension getExtensionObject() {
+        return this.ext;
+    }
+    
+    /**
+     * {@inheritDoc}
+     * @return  {@link PDFExtensionElementMapping#URI}
+     */
+    public String getCategory() {
+        return PDFExtensionElementMapping.URI;
+    }
+}

Property changes on: src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionAttachment.java
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java
===================================================================
--- src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java	(revision 0)
+++ src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java	(revision 0)
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* $Id$ */
+package org.apache.fop.fo.extensions.pdf;
+
+import org.apache.fop.fo.extensions.ExtensionElementMapping;
+import org.apache.fop.fo.ElementMapping;
+import org.apache.fop.fo.FONode;
+
+import java.util.HashMap;
+
+public class PDFExtensionElementMapping extends ExtensionElementMapping {
+    
+    /** The FOP PDF extension namespace URI */
+    public static final String URI = "http://xmlgraphics.apache.org/fop/extensions/pdf";
+    
+    /** The standard namespace prefix */
+    public static final String PREFIX = "pdf";
+    /**
+     * Constructor.
+     */
+    public PDFExtensionElementMapping() {
+        namespaceURI = URI;
+    }
+
+    /**
+     * Initialize the data structures.
+     */
+    protected void initialize() {
+        if (foObjs == null) {
+            foObjs = new HashMap();
+            foObjs.put("dictionary", new PDFDictionaryExtensionMaker());
+            foObjs.put("entry", new PDFEntryExtensionMaker());
+        }
+    }
+
+    /** Inner class for making instances of {@link PDFDictionaryExtension} */
+    static class PDFDictionaryExtensionMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFDictionaryExtension(parent);
+        }
+    }
+
+    /** Inner class for making instances of {@link PDFEntryExtension} */
+    static class PDFEntryExtensionMaker extends ElementMapping.Maker {
+        public FONode make(FONode parent) {
+            return new PDFEntryExtension(parent);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public String getStandardPrefix() {
+        return PREFIX;
+    }
+
+}

Property changes on: src/java/org/apache/fop/fo/extensions/pdf/PDFExtensionElementMapping.java
___________________________________________________________________
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Index: src/java/org/apache/fop/render/pdf/PDFRenderer.java
===================================================================
--- src/java/org/apache/fop/render/pdf/PDFRenderer.java	(revision 676141)
+++ src/java/org/apache/fop/render/pdf/PDFRenderer.java	(working copy)
@@ -76,6 +76,11 @@
 import org.apache.fop.events.ResourceEventProducer;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.extensions.pdf.AbstractPDFExtension;
+import org.apache.fop.fo.extensions.pdf.PDFDictionaryExtension;
+import org.apache.fop.fo.extensions.pdf.PDFEntryExtension;
+import org.apache.fop.fo.extensions.pdf.PDFExtensionAttachment;
+import org.apache.fop.fo.extensions.pdf.PDFExtensionElementMapping;
 import org.apache.fop.fo.extensions.xmp.XMPMetadata;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.fonts.LazyFont;
@@ -98,6 +103,7 @@
 import org.apache.fop.pdf.PDFInfo;
 import org.apache.fop.pdf.PDFLink;
 import org.apache.fop.pdf.PDFMetadata;
+import org.apache.fop.pdf.PDFName;
 import org.apache.fop.pdf.PDFNumber;
 import org.apache.fop.pdf.PDFNumsArray;
 import org.apache.fop.pdf.PDFOutline;
@@ -548,6 +554,9 @@
             if (XMPMetadata.CATEGORY.equals(attachment.getCategory())) {
                 renderXMPMetadata((XMPMetadata)attachment);
             }
+            if (PDFExtensionElementMapping.URI.equals(attachment.getCategory())) {
+                renderPDFExtension((PDFExtensionAttachment)attachment);
+            }
         }
     }
 
@@ -621,6 +630,29 @@
         pdfDoc.getRoot().setMetadata(pdfMetadata);
     }
 
+    private void renderPDFExtension(PDFExtensionAttachment ext) {
+        AbstractPDFExtension extNode = ext.getExtensionObject();
+        if (extNode instanceof PDFDictionaryExtension) {
+            PDFDictionaryExtension dict = (PDFDictionaryExtension)extNode;
+            if (dict.getType() == PDFDictionaryExtension.TYPE_CATALOG) {
+                //add the entries/subdictionaries to pdfDoc.getRoot()
+                AbstractPDFExtension entry;
+                PDFExtensionAttachment att;
+                for (Iterator entryIter = dict.getExtensionAttachments().iterator(); entryIter.hasNext();) {
+                    att = (PDFExtensionAttachment)entryIter.next();
+                    entry = att.getExtensionObject();
+                    if (entry instanceof PDFEntryExtension) {
+                        pdfDoc.getRoot().put(
+                                ((PDFEntryExtension)entry).getEntryName(),
+                                new PDFName(((PDFEntryExtension)entry).getEntryValue()));
+                    }
+                }
+            } else {
+                //TODO??
+            }
+        }
+    }
+    
     /** {@inheritDoc} */
     public Graphics2DAdapter getGraphics2DAdapter() {
         return new PDFGraphics2DAdapter(this);
