Index: src/java/org/apache/fop/pdf/PDFAction.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFAction.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFAction.java	(working copy)
@@ -22,18 +22,13 @@
 /**
  * class representing an action object.
  */
-public abstract class PDFAction extends PDFObject {
-
-
+public abstract class PDFAction extends PDFDictionary {
+    
     /**
-     * represent the action to call
-     * this method should be implemented to return the action which gets
-     * called by the Link Object.  This could be a reference to another object
-     * or the specific destination of the link
-     *
-     * @return the action to place next to /A within a Link
+     * Default constructor
      */
-    public abstract String getAction();
-
-
+    public PDFAction() {
+        super();
+        this.put("Type", new PDFName("Action"));
+    }
 }
Index: src/java/org/apache/fop/pdf/PDFArray.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFArray.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFArray.java	(working copy)
@@ -189,4 +189,18 @@
         return cout.getCount();
     }
 
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return (this == o)
+            || (o instanceof PDFArray
+                && (this.values == ((PDFArray)o).values
+                    || (this.values != null
+                        && this.values.equals(((PDFArray)o).values))));
+
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return 17 * 37 + this.values.hashCode();
+    }
 }
Index: src/java/org/apache/fop/pdf/PDFDestination.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFDestination.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFDestination.java	(working copy)
@@ -117,11 +117,7 @@
         }
 
         PDFDestination dest = (PDFDestination)obj;
-        if (dest.getIDRef().equals(this.getIDRef())) {
-            return true;
-        }
-
-        return false;
+        return (dest.getIDRef().equals(this.getIDRef()));
     }
 
     /** {@inheritDoc} */
Index: src/java/org/apache/fop/pdf/PDFDictionary.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFDictionary.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFDictionary.java	(working copy)
@@ -90,6 +90,18 @@
     }
 
     /**
+     * Puts a new name/value pair.
+     * @param name the name
+     * @param value the value
+     */
+    public void put(String name, boolean value) {
+        if (!entries.containsKey(name)) {
+            this.order.add(name);
+        }
+        this.entries.put(name, value ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    /**
      * Returns the value given a name.
      * @param name the name of the value
      * @return the value or null, if there's no value with the given name.
@@ -147,4 +159,18 @@
         writer.write(">>\n");
     }
 
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return 37 * 17 + this.entries.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return this == o
+            || (o != null
+                && this.getClass() == o.getClass()
+                && (this.entries == ((PDFDictionary)o).entries
+                    || (this.entries != null
+                        && this.entries.equals(((PDFDictionary)o).entries))));
+    }
 }
Index: src/java/org/apache/fop/pdf/PDFDocument.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFDocument.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFDocument.java	(working copy)
@@ -870,7 +870,7 @@
             return this.outlineRoot;
         }
 
-        this.outlineRoot = new PDFOutline(null, null, true);
+        this.outlineRoot = new PDFOutline(null, (PDFAction)null, true);
         assignObjectNumber(this.outlineRoot);
         addTrailerObject(this.outlineRoot);
         this.root.setRootOutline(this.outlineRoot);
Index: src/java/org/apache/fop/pdf/PDFFactory.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFFactory.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFFactory.java	(working copy)
@@ -953,11 +953,9 @@
         PDFLink link = new PDFLink(rect);
         getDocument().registerObject(link);
 
-        PDFGoTo gt = new PDFGoTo(page);
+        PDFGoTo gt = new PDFGoTo(new PDFReference(page));
         gt.setDestination(dest);
-        getDocument().addTrailerObject(gt);
-        PDFInternalLink internalLink = new PDFInternalLink(gt.referencePDF());
-        link.setAction(internalLink);
+        link.setAction(gt);
 
         return link;
     }
@@ -981,9 +979,9 @@
             link.setAction(getExternalAction(destination, false));
         } else {
             // linkType is internal
-            String goToReference = getGoToReference(destination, yoffset);
-            PDFInternalLink internalLink = new PDFInternalLink(goToReference);
-            link.setAction(internalLink);
+            PDFGoTo gt = new PDFGoTo(new PDFReference(destination),
+                                     new Point2D.Float(0, yoffset));
+            link.setAction(gt);
         }
 
         PDFLink oldlink = getDocument().findLink(link);
@@ -1010,8 +1008,9 @@
         String targetLo = target.toLowerCase();
         // HTTP URL?
         if (targetLo.startsWith("http://")) {
+            //return getUriAction(target);
             return new PDFUri(target);
-        // Non PDF files. Try to /Launch them.
+        // file:// protocol. Try to launch the file.
         } else if (targetLo.startsWith("file://")) {
             target = target.substring("file://".length());
             return getLaunchAction(target);
@@ -1031,6 +1030,7 @@
         // None of the above? Default to URI:
         } else {
             return new PDFUri(target);
+            //return getUriAction(target);
         }
     }
 
@@ -1057,7 +1057,7 @@
      */
     public PDFGoTo getPDFGoTo(String pdfPageRef, Point2D position) {
         getDocument().getProfile().verifyActionAllowed();
-        PDFGoTo gt = new PDFGoTo(pdfPageRef, position);
+        PDFGoTo gt = new PDFGoTo(new PDFReference(pdfPageRef), position);
         PDFGoTo oldgt = getDocument().findGoTo(gt);
         if (oldgt == null) {
             getDocument().assignObjectNumber(gt);
@@ -1140,6 +1140,32 @@
     }
 
     /**
+     * Returns a {@link PDFUri} object for a given target string.
+     * If the object does not yet exist, it is created and registered.
+     * Otherwise, the registered instance is returned.
+     *
+     * @param target   the target
+     * @return the corresponding {@link PDFUri} object
+     */
+    /*
+    public PDFUri getUriAction(String target) {
+        //TODO: Check if necessary for URI actions?
+        getDocument().getProfile().verifyActionAllowed();
+
+        PDFUri uri = new PDFUri(target);
+        PDFUri oldUri = getDocument().findURI(uri);
+
+        if (oldUri == null) {
+            getDocument().registerObject(uri);
+        } else {
+            uri = oldUri;
+        }
+
+        return uri;
+    }
+    */
+
+    /**
      * Make an outline object and add it to the given parent
      *
      * @param parent the parent PDFOutline object (may be null)
@@ -1147,6 +1173,7 @@
      * @param actionRef the action reference string to be placed after the /A
      * @param showSubItems whether to initially display child outline items
      * @return the new PDF outline object
+     * @deprecated use {@link #makeOutline(PDFOutline, String, PDFAction, boolean)} instead
      */
     public PDFOutline makeOutline(PDFOutline parent, String label,
                                   String actionRef, boolean showSubItems) {
@@ -1169,31 +1196,14 @@
      */
     public PDFOutline makeOutline(PDFOutline parent, String label,
                                   PDFAction pdfAction, boolean showSubItems) {
-        return pdfAction == null
-                 ? null
-                 : makeOutline(parent, label, pdfAction.getAction(), showSubItems);
+        PDFOutline pdfOutline = new PDFOutline(label, pdfAction, showSubItems);
+        if (parent != null) {
+            parent.addOutline(pdfOutline);
+        }
+        getDocument().registerObject(pdfOutline);
+        return pdfOutline;
     }
 
-    // This one is obsolete now, at least it isn't called from anywhere inside FOP
-    /**
-     * Make an outline object and add it to the given outline
-     *
-     * @param parent parent PDFOutline object which may be null
-     * @param label the title for the new outline object
-     * @param destination the reference string for the action to go to
-     * @param yoffset the yoffset on the destination page
-     * @param showSubItems whether to initially display child outline items
-     * @return the new PDF outline object
-     */
-    public PDFOutline makeOutline(PDFOutline parent, String label,
-                                  String destination, float yoffset,
-                                  boolean showSubItems) {
-
-        String goToRef = getGoToReference(destination, yoffset);
-        return makeOutline(parent, label, goToRef, showSubItems);
-    }
-
-
     /* ========================= fonts ===================================== */
 
     /**
Index: src/java/org/apache/fop/pdf/PDFFileSpec.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFFileSpec.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFFileSpec.java	(working copy)
@@ -23,68 +23,17 @@
  * class representing a /FileSpec object.
  *
  */
-public class PDFFileSpec extends PDFObject {
+public class PDFFileSpec extends PDFDictionary {
 
     /**
-     * the filename
-     */
-    protected String filename;
-
-    /**
-     * create a /FileSpec object.
+     * Construct a /FileSpec object.
      *
      * @param filename the filename represented by this object
      */
     public PDFFileSpec(String filename) {
-
-        /* generic creation of object */
         super();
-
-        this.filename = filename;
+        this.put("Type", new PDFName("FileSpec"));
+        this.put("F", new PDFString(filename));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String toPDFString() {
-        return getObjectID()
-                + "<<\n/Type /FileSpec\n"
-                + "/F (" + this.filename + ")\n"
-                + ">>\nendobj\n";
-    }
-
-    /*
-     * example
-     * 29 0 obj
-     * <<
-     * /Type /FileSpec
-     * /F (table1.pdf)
-     * >>
-     * endobj
-     */
-
-    /**
-     * Check if this equals another object.
-     *
-     * @param obj the object to compare
-     * @return true if this equals other object
-     */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || !(obj instanceof PDFFileSpec)) {
-            return false;
-        }
-
-        PDFFileSpec spec = (PDFFileSpec)obj;
-
-        if (!spec.filename.equals(filename)) {
-            return false;
-        }
-
-        return true;
-    }
 }
 
Index: src/java/org/apache/fop/pdf/PDFGoTo.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFGoTo.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFGoTo.java	(working copy)
@@ -20,6 +20,9 @@
 package org.apache.fop.pdf;
 
 import java.awt.geom.Point2D;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.io.IOException;
 
 /**
  * class representing a /GoTo object.
@@ -28,37 +31,52 @@
  */
 public class PDFGoTo extends PDFAction {
 
-    /**
-     * the pageReference
-     */
-    private String pageReference;
+    /** the pageReference */
+    private PDFReference pageReference;
     private String destination = null;
     private float xPosition = 0;
     private float yPosition = 0;
 
     /**
-     * create a /GoTo object.
+     * Construct a /GoTo object.
      *
      * @param pageReference the pageReference represented by this object
+     * @deprecated use {@link PDFGoTo(PDFReference)} instead
      */
     public PDFGoTo(String pageReference) {
-        /* generic creation of object */
-        super();
+        this(new PDFReference(pageReference));
+    }
 
-        this.pageReference = pageReference;
+    /**
+     * Construct a /GoTo object
+     *
+     * @param pageReference the pageReference represented by this object
+     */
+    public PDFGoTo(PDFReference pageReference) {
+        super();
+        this.put("S", new PDFName("GoTo"));
+        setPageReference(pageReference);
     }
 
     /**
-     * create a /GoTo object.
+     * Construct a /GoTo object.
      *
      * @param pageReference the PDF reference to the target page
      * @param position the target area's on-page coordinates in points
+     * @deprecated use {@link PDFGoTo(PDFReference, Point2D)} instead
      */
     public PDFGoTo(String pageReference, Point2D position) {
-        /* generic creation of object */
-        super();
+        this(new PDFReference(pageReference), position);
+    }
 
-        this.pageReference = pageReference;
+    /**
+     * Construct a /GoTo object.
+     *
+     * @param pageReference the PDF reference to the target page
+     * @param position the target area's on-page coordinates in points
+     */
+    public PDFGoTo(PDFReference pageReference, Point2D position) {
+        this(pageReference);
         setPosition(position);
     }
 
@@ -66,8 +84,18 @@
      * Sets page reference after object has been created
      *
      * @param pageReference the new page reference to use
+     * @deprecated use {@link #setPageReference(PDFReference)} instead
      */
     public void setPageReference(String pageReference) {
+        this.setPageReference(new PDFReference(pageReference));
+    }
+
+    /**
+     * Sets page reference after object has been created
+     *
+     * @param pageReference the new page reference to use
+     */
+    public void setPageReference(PDFReference pageReference) {
         this.pageReference = pageReference;
     }
 
@@ -108,80 +136,21 @@
         destination = dest;
     }
 
-    /**
-     * Get the PDF reference for the GoTo action.
-     *
-     * @return the PDF reference for the action
-     */
-    public String getAction() {
-        return referencePDF();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String toPDFString() {
-        String dest;
-        if (destination == null) {
-            dest = "/D [" + this.pageReference + " /XYZ " + xPosition
-                          + " " + yPosition + " null]\n";
+    /** {@inheritDoc} */
+    protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
+        if (this.destination == null) {
+            this.put("D", new PDFArray(this, new Object[]{
+                    this.pageReference,
+                    new PDFName("XYZ"),
+                    new Float(this.xPosition),
+                    new Float(this.yPosition),
+                    null }));
         } else {
-            dest = "/D [" + this.pageReference + " " + destination + "]\n";
+            this.put("D", new PDFArray(this, new Object[]{
+                    this.pageReference,
+                    this.destination }));
         }
-        return getObjectID()
-                    + "<< /Type /Action\n/S /GoTo\n" + dest
-                    + ">>\nendobj\n";
+        super.writeDictionary(out, writer);
     }
-
-    /*
-     * example
-     * 29 0 obj
-     * <<
-     * /S /GoTo
-     * /D [23 0 R /FitH 600]
-     * >>
-     * endobj
-     */
-
-    /**
-     * Check if this equals another object.
-     *
-     * @param obj the object to compare
-     * @return true if this equals other object
-     */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || !(obj instanceof PDFGoTo)) {
-            return false;
-        }
-
-        PDFGoTo gt = (PDFGoTo)obj;
-
-        if (gt.pageReference == null) {
-            if (pageReference != null) {
-                return false;
-            }
-        } else {
-            if (!gt.pageReference.equals(pageReference)) {
-                return false;
-            }
-        }
-
-        if (destination == null) {
-            if (!(gt.destination == null && gt.xPosition == xPosition
-                && gt.yPosition == yPosition)) {
-                return false;
-            }
-        } else {
-            if (!destination.equals(gt.destination)) {
-                return false;
-            }
-        }
-
-        return true;
-    }
 }
 
Index: src/java/org/apache/fop/pdf/PDFGoToRemote.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFGoToRemote.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFGoToRemote.java	(working copy)
@@ -25,30 +25,26 @@
 public class PDFGoToRemote extends PDFAction {
 
     /**
-     * the file specification
+     * Create a /GoToR object
      */
-    private PDFFileSpec pdfFileSpec;
-    private int pageReference = 0;
-    private String destination = null;
-    private boolean newWindow = false;
+    public PDFGoToRemote() {
+        super();
+        this.put("S", new PDFName("GoToR"));
+    }
 
     /**
-     * Create an GoToR object.
+     * Create a /GoToR object.
      *
      * @param pdfFileSpec the fileSpec associated with the action
      * @param newWindow boolean indicating whether the target should be
      *                  displayed in a new window
      */
     public PDFGoToRemote(PDFFileSpec pdfFileSpec, boolean newWindow) {
-        /* generic creation of object */
-        super();
-
-        this.pdfFileSpec = pdfFileSpec;
-        this.newWindow = newWindow;
+        this(pdfFileSpec, 0, newWindow);
     }
 
     /**
-     * create an GoToR object.
+     * Create a /GoToR object.
      *
      * @param pdfFileSpec the fileSpec associated with the action
      * @param page a page reference within the remote document
@@ -56,16 +52,17 @@
      *                  displayed in a new window
      */
     public PDFGoToRemote(PDFFileSpec pdfFileSpec, int page, boolean newWindow) {
-        /* generic creation of object */
-        super();
-
-        this.pdfFileSpec = pdfFileSpec;
-        this.pageReference = page;
-        this.newWindow = newWindow;
+        this();
+        this.setFileSpec(pdfFileSpec);
+        this.setNewWindow(newWindow);
+        this.put("D", new PDFArray(this, new Object[]{
+                new Integer(page),
+                new PDFName("XYZ"),
+                null, null, null }));
     }
 
     /**
-     * create an GoToR object.
+     * Create a /GoToR object.
      *
      * @param pdfFileSpec the fileSpec associated with the action
      * @param dest a named destination within the remote document
@@ -73,92 +70,28 @@
      *                  displayed in a new window
      */
     public PDFGoToRemote(PDFFileSpec pdfFileSpec, String dest, boolean newWindow) {
-        /* generic creation of object */
-        super();
-
-        this.pdfFileSpec = pdfFileSpec;
-        this.destination = dest;
-        this.newWindow = newWindow;
+        this();
+        this.setFileSpec(pdfFileSpec);
+        this.setNewWindow(newWindow);
+        this.put("D", dest);
     }
 
     /**
-     * return the action string which will reference this object
+     * Sets the /F entry
      *
-     * @return the action String
+     * @param   pdfFileSpec the new value for the entry
      */
-    public String getAction() {
-        return this.referencePDF();
+    public void setFileSpec(PDFFileSpec pdfFileSpec) {
+        this.put("F", pdfFileSpec);
     }
 
     /**
-     * {@inheritDoc}
-     */
-    public String toPDFString() {
-        StringBuffer sb = new StringBuffer(64);
-        sb.append(getObjectID());
-        sb.append("<<\n/S /GoToR\n/F ");
-        sb.append(pdfFileSpec.referencePDF());
-        sb.append("\n");
-
-        if (destination != null) {
-            sb.append("/D (").append(this.destination).append(")");
-        } else {
-            sb.append("/D [ ").append(this.pageReference).append(" /XYZ null null null ]");
-        }
-
-        if (newWindow) {
-            sb.append("/NewWindow true");
-        }
-
-        sb.append(" \n>>\nendobj\n");
-
-        return sb.toString();
-    }
-
-
-    /*
-     * example
-     * 28 0 obj
-     * <<
-     * /S /GoToR
-     * /F 29 0 R
-     * /D [ 0 /XYZ -6 797 null ]
-     * >>
-     * endobj
-     */
-
-    /**
-     * Check if this equals another object.
+     * Sets the /NewWindow entry
      *
-     * @param obj the object to compare
-     * @return true if this equals other object
+     * @param   newWindow the new value for the entry
      */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || !(obj instanceof PDFGoToRemote)) {
-            return false;
-        }
-
-        PDFGoToRemote remote = (PDFGoToRemote)obj;
-
-        if (!remote.pdfFileSpec.referencePDF().equals(pdfFileSpec.referencePDF())) {
-            return false;
-        }
-
-        if (destination != null) {
-            if (!destination.equals(remote.destination)) {
-                return false;
-            }
-        } else {
-            if (pageReference != remote.pageReference) {
-                return false;
-            }
-        }
-
-        return (this.newWindow == remote.newWindow);
+    public void setNewWindow(boolean newWindow) {
+        this.put("NewWindow", Boolean.valueOf(newWindow));
     }
 }
 
Index: src/java/org/apache/fop/pdf/PDFLaunch.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFLaunch.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFLaunch.java	(working copy)
@@ -22,47 +22,9 @@
  */
 public class PDFLaunch extends PDFAction {
 
-    private PDFFileSpec externalFileSpec;
-
     public PDFLaunch(PDFFileSpec fileSpec) {
-        this.externalFileSpec = fileSpec;
+        super();
+        this.put("S", new PDFName("Launch"));
+        this.put("F", fileSpec);
     }
-
-    public String getAction() {
-        return this.referencePDF();
-    }
-
-    public String toPDFString() {
-        StringBuffer sb = new StringBuffer(64);
-        sb.append(getObjectID());
-        sb.append("<<\n/S /Launch\n/F ");
-        sb.append(externalFileSpec.referencePDF());
-        sb.append(" \n>>\nendobj\n");
-
-        return sb.toString();
-    }
-
-    /**
-     * Check if this equals another object.
-     *
-     * @param obj the object to compare
-     * @return true if this equals other object
-     */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || !(obj instanceof PDFLaunch)) {
-            return false;
-        }
-
-        PDFLaunch launch = (PDFLaunch) obj;
-
-        if (!launch.externalFileSpec.referencePDF().equals(externalFileSpec.referencePDF())) {
-            return false;
-        }
-
-        return true;
-    }
 }
Index: src/java/org/apache/fop/pdf/PDFLink.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFLink.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFLink.java	(working copy)
@@ -21,11 +21,15 @@
 
 // Java
 import java.awt.geom.Rectangle2D;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.io.IOException;
 
 /**
  * class representing an /Annot object of /Subtype /Link
  */
-public class PDFLink extends PDFObject {
+public class PDFLink extends PDFDictionary {
+
     /**
      * Used to represent an external link.
      */
@@ -36,104 +40,48 @@
      */
     public static final int INTERNAL = 1;
 
-    private float ulx;
-    private float uly;
-    private float brx;
-    private float bry;
-    private String color;
-    private PDFAction action;
-
     /**
-     * create objects associated with a link annotation (GoToR)
+     * Default constructor
+     */
+    public PDFLink() {
+        super();
+        this.put("Type", new PDFName("Annot"));
+        this.put("Subtype", new PDFName("Link"));
+    }
+    /**
+     * Create objects associated with a link annotation (GoToR)
      *
      * @param r the rectangle of the link hotspot in absolute coordinates
      */
     public PDFLink(Rectangle2D r) {
-        /* generic creation of PDF object */
-        super();
-
-        this.ulx = (float)r.getX();
-        this.uly = (float)r.getY();
-        this.brx = (float)(r.getX() + r.getWidth());
-        this.bry = (float)(r.getY() + r.getHeight());
-        this.color = "0 0 0";    // just for now
-
+        this();
+        this.put("Rect", new PDFArray(this, new double[]
+                     {r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY()}));
+        this.put("C", new PDFArray(this, new int[] {0, 0, 0})); //just for now
+        this.put("Border", new PDFArray(this, new int[] {0, 0, 0})); //just for now
+        this.put("H", new PDFName("I")); //Invert
     }
 
     /**
      * Set the pdf action for this link.
+     *
      * @param action the pdf action that is activated for this link
      */
     public void setAction(PDFAction action) {
-        this.action = action;
+        this.put("A", action);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    public String toPDFString() {
+    /** {@inheritDoc} */
+    protected void writeDictionary(OutputStream out, Writer writer) throws IOException {
         getDocumentSafely().getProfile().verifyAnnotAllowed();
-        String fFlag = "";
         if (getDocumentSafely().getProfile().getPDFAMode().isPDFA1LevelB()) {
             int f = 0;
             f |= 1 << (3 - 1); //Print, bit 3
             f |= 1 << (4 - 1); //NoZoom, bit 4
             f |= 1 << (5 - 1); //NoRotate, bit 5
-            fFlag = "/F " + f;
+            this.put("F", f);
         }
-        String s = getObjectID()
-                   + "<< /Type /Annot\n" + "/Subtype /Link\n" + "/Rect [ "
-                   + (ulx) + " " + (uly) + " "
-                   + (brx) + " " + (bry) + " ]\n" + "/C [ "
-                   + this.color + " ]\n" + "/Border [ 0 0 0 ]\n" + "/A "
-                   + this.action.getAction() + "\n" + "/H /I\n"
-                   + fFlag + "\n>>\nendobj\n";
-        return s;
+        super.writeDictionary(out, writer);
     }
-
-    /*
-     * example
-     * 19 0 obj
-     * <<
-     * /Type /Annot
-     * /Subtype /Link
-     * /Rect [ 176.032 678.48412 228.73579 692.356 ]
-     * /C [ 0.86491 0.03421 0.02591 ]
-     * /Border [ 0 0 1 ]
-     * /A 28 0 R
-     * /H /I
-     * >>
-     * endobj
-     */
-
-    /**
-     * Check if this equals another object.
-     *
-     * @param obj the object to compare
-     * @return true if this equals other object
-     */
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-
-        if (obj == null || !(obj instanceof PDFLink)) {
-            return false;
-        }
-
-        PDFLink link = (PDFLink)obj;
-
-        if (!((link.ulx == ulx) && (link.uly == uly)
-              && (link.brx == brx) && (link.bry == bry))) {
-            return false;
-        }
-
-        if (!(link.color.equals(color)
-             && link.action.getAction().equals(action.getAction()))) {
-            return false;
-        }
-
-        return true;
-    }
 }
 
Index: src/java/org/apache/fop/pdf/PDFName.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFName.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFName.java	(working copy)
@@ -41,7 +41,6 @@
         this.name = escapeName(name);
     }
 
-
     private static String escapeName(String name) {
         StringBuffer sb = new StringBuffer(Math.min(16, name.length() + 4));
         if (!name.startsWith("/")) {
@@ -104,4 +103,17 @@
         }
     }
 
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return this.name.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return (this == o)
+            || (o instanceof PDFName
+                && this.name == ((PDFName)o).name
+                    || (this.name != null
+                        && this.name.equals(((PDFName)o).name)));
+    }
 }
Index: src/java/org/apache/fop/pdf/PDFNumber.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFNumber.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFNumber.java	(working copy)
@@ -70,13 +70,13 @@
     private static final String BASE_FORMAT = "0.################";
 
     private static class DecimalFormatThreadLocal extends ThreadLocal {
-        
+
         private int dec;
-        
+
         public DecimalFormatThreadLocal(int dec) {
             this.dec = dec;
         }
-        
+
         protected synchronized Object initialValue() {
             String s = "0";
             if (dec > 0) {
@@ -93,7 +93,7 @@
             DECIMAL_FORMAT_CACHE[i] = new DecimalFormatThreadLocal(i);
         }
     }
-    
+
     /**
      * Output a double value to a string suitable for PDF.
      * In this method it is possible to set the maximum
@@ -129,5 +129,18 @@
         return sb.toString();
     }
 
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return this.number.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return (this == o)
+            || (o instanceof PDFNumber
+                && (this.number == ((PDFNumber)o).number
+                    || (this.number != null
+                        && this.number.equals(((PDFNumber)o).number))));
+    }
 }
 
Index: src/java/org/apache/fop/pdf/PDFObject.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFObject.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFObject.java	(working copy)
@@ -44,6 +44,8 @@
     /** logger for all PDFObjects (and descendants) */
     protected static Log log = LogFactory.getLog(PDFObject.class.getName());
 
+    //public abstract boolean equals(Object o);
+
     /**
      * the object's number
      */
@@ -190,8 +192,7 @@
             throw new IllegalArgumentException(
                     "Cannot reference this object. It doesn't have an object number");
         }
-        String ref = getObjectNumber() + " " + getGeneration() + " R";
-        return ref;
+        return getObjectNumber() + " " + getGeneration() + " R";
     }
 
     /**
@@ -280,7 +281,13 @@
      * @return byte[] the encoded string
      */
     protected byte[] encodeString(String string) {
-        return encodeText(string);
+        if (getDocumentSafely().isEncryptionActive()) {
+            final byte[] buf = PDFDocument.encode(string);
+            return PDFText.escapeByteArray(
+                getDocument().getEncryption().encrypt(buf, this));
+        } else {
+            return encode(PDFText.escapeText(string, false));
+        }
     }
 
     /**
@@ -324,6 +331,9 @@
         } else if (obj instanceof byte[]) {
             writer.flush();
             encodeBinaryToHexString((byte[])obj, out);
+        } else if (obj instanceof PDFString) {
+            writer.flush();
+            out.write(encodeString(((PDFString)obj).getText()));
         } else {
             writer.flush();
             out.write(encodeText(obj.toString()));
Index: src/java/org/apache/fop/pdf/PDFOutline.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFOutline.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFOutline.java	(working copy)
@@ -62,6 +62,19 @@
     private String actionRef;
 
     /**
+     * Default constructor
+     */
+    public PDFOutline() {
+        super();
+        this.subentries = new java.util.ArrayList();
+        this.count = 0;
+        this.parent = null;
+        this.prev = null;
+        this.first = null;
+        this.last = null;
+    }
+
+    /**
      * Create a PDF outline with the title and action.
      *
      * @param title the title of the outline entry (can only be null for root Outlines obj)
@@ -69,20 +82,24 @@
      * @param openItem indicator of whether child items are visible or not
      */
     public PDFOutline(String title, String action, boolean openItem) {
-        super();
-        subentries = new java.util.ArrayList();
-        count = 0;
-        parent = null;
-        prev = null;
-        next = null;
-        first = null;
-        last = null;
+        this();
         this.title = title;
-        actionRef = action;
+        this.actionRef = action;
         this.openItem = openItem;
     }
 
     /**
+     * Create a PDF outline with the title and action.
+     *
+     * @param title the title of the outline entry (can only be null for root Outlines obj)
+     * @param action the action for this outline
+     * @param openItem indicator of whether child items are visible or not
+     */
+    public PDFOutline(String title, PDFAction action, boolean openItem) {
+        this(title, (action != null ? action.referencePDF() : null), openItem);
+    }
+
+    /**
      * Set the title of this Outline object.
      *
      * @param t the title of the outline
Index: src/java/org/apache/fop/pdf/PDFReference.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFReference.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFReference.java	(working copy)
@@ -83,4 +83,17 @@
         writer.write(toString());
     }
 
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return this.indirectReference.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return this == o
+            || (o instanceof PDFReference
+                && (this.indirectReference == ((PDFReference)o).indirectReference
+                    || (this.indirectReference != null
+                        && this.indirectReference.equals(((PDFReference)o).indirectReference))));
+    }
 }
Index: src/java/org/apache/fop/pdf/PDFString.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFString.java	(revision 0)
+++ src/java/org/apache/fop/pdf/PDFString.java	(revision 0)
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.pdf;
+
+/**
+ * Class representing a "string" object in PDF. Normally, the PDF library treats
+ * {@link java.lang.String} as "text string" objects. In some cases, however, the
+ * PDF spec requires "string" objects which need to be treated differently,
+ * especially in the case of encryption. For the formatting, see {@link PDFObject}.
+ */
+public class PDFString {
+
+    private final String text;
+
+    /**
+     * Creates a new "string" object.
+     * @param text the text
+     */
+    public PDFString(String text) {
+        this.text = text;
+    }
+
+    /**
+     * Returns the string object's text.
+     * @return the text
+     */
+    public String getText() {
+        return this.text;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return "(" + getText() + ")";
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return this.text.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        return (this == o
+            || (o instanceof PDFString
+                && (this.text == ((PDFString)o).text
+                    || (this.text != null
+                        && this.text.equals(((PDFString)o).text)))));
+    }
+}

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

Index: src/java/org/apache/fop/pdf/PDFUri.java
===================================================================
--- src/java/org/apache/fop/pdf/PDFUri.java	(revision 724434)
+++ src/java/org/apache/fop/pdf/PDFUri.java	(working copy)
@@ -20,35 +20,25 @@
 package org.apache.fop.pdf;
 
 /**
- * class used to create a PDF Uri link
+ * class used to create a PDF URI Action (link to an external resource/website)
  */
 public class PDFUri extends PDFAction {
 
-    private String uri;
-
     /**
-     * create a Uri instance.
-     *
-     * @param uri the uri to which the link should point
+     * Default constructor
      */
-    public PDFUri(String uri) {
-        this.uri = uri;
+    public PDFUri() {
+        super();
+        this.put("S", new PDFName("URI"));
     }
 
     /**
-     * returns the action ncecessary for a uri
+     * Create a PDFUri instance.
      *
-     * @return the action to place next to /A within a Link
+     * @param uri the uri to which the link should point
      */
-    public String getAction() {
-        return "<< /URI (" + uri + ")\n/S /URI >>";
+    public PDFUri(String uri) {
+        this();
+        this.put("URI", new PDFString(uri));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    public String toPDFString() {
-        throw new UnsupportedOperationException("This method should not be called");
-    }
-
 }
