]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
My first attempt at implementing links was messed up. This second attempt actually...
authorJeremias Maerki <jeremias@apache.org>
Thu, 11 Dec 2008 14:15:32 +0000 (14:15 +0000)
committerJeremias Maerki <jeremias@apache.org>
Thu, 11 Dec 2008 14:15:32 +0000 (14:15 +0000)
Optimized IF serialization a bit: only real changes in the IF state are serialized to the IF (makes smaller files and results in higher performance).

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@725690 13f79535-47bb-0310-9956-ffa450edef68

14 files changed:
src/java/org/apache/fop/render/intermediate/IFRenderer.java
src/java/org/apache/fop/render/intermediate/IFSerializer.java
src/java/org/apache/fop/render/intermediate/extensions/AbstractAction.java
src/java/org/apache/fop/render/intermediate/extensions/ActionSet.java
src/java/org/apache/fop/render/intermediate/extensions/Bookmark.java
src/java/org/apache/fop/render/intermediate/extensions/BookmarkTree.java
src/java/org/apache/fop/render/intermediate/extensions/DocumentNavigationExtensionConstants.java
src/java/org/apache/fop/render/intermediate/extensions/GoToXYAction.java
src/java/org/apache/fop/render/intermediate/extensions/Link.java
src/java/org/apache/fop/render/intermediate/extensions/NamedDestination.java
src/java/org/apache/fop/render/intermediate/extensions/ReferencedAction.java [deleted file]
src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
src/java/org/apache/fop/render/pdf/PDFDocumentNavigationHandler.java
src/java/org/apache/fop/util/GenerationHelperContentHandler.java

index 4b2b043956abe2487a3cfd84a0e4d3e4172471c0..b3748dc2e94c2784508f0d309f58e2c7c392e7fe 100644 (file)
@@ -142,6 +142,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
     // can't use a Set because PDFGoTo.equals returns true if the target is the same,
     // even if the object number differs
 
+    /** Maps unique PageViewport key to page indices (for link target handling) */
+    protected Map pageIndices = new java.util.HashMap();
+
     private BookmarkTree bookmarkTree;
     private List deferredDestinations = new java.util.ArrayList();
     private List deferredLinks = new java.util.ArrayList();
@@ -267,21 +270,18 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
             documentHandler.startDocumentTrailer();
 
             //Wrap up document navigation
-            finishOpenGoTos();
-            Iterator iter;
-            iter = this.actionSet.getActions();
-            while (iter.hasNext()) {
-                getDocumentNavigationHandler().addResolvedAction((AbstractAction)iter.next());
-            }
-            iter = this.deferredDestinations.iterator();
-            while (iter.hasNext()) {
-                NamedDestination dest = (NamedDestination)iter.next();
-                iter.remove();
-                getDocumentNavigationHandler().renderNamedDestination(dest);
-            }
+            if (hasDocumentNavigation()) {
+                finishOpenGoTos();
+                Iterator iter = this.deferredDestinations.iterator();
+                while (iter.hasNext()) {
+                    NamedDestination dest = (NamedDestination)iter.next();
+                    iter.remove();
+                    getDocumentNavigationHandler().renderNamedDestination(dest);
+                }
 
-            if (this.bookmarkTree != null) {
-                getDocumentNavigationHandler().renderBookmarkTree(this.bookmarkTree);
+                if (this.bookmarkTree != null) {
+                    getDocumentNavigationHandler().renderBookmarkTree(this.bookmarkTree);
+                }
             }
 
             documentHandler.endDocumentTrailer();
@@ -289,6 +289,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         } catch (IFException e) {
             handleIFExceptionWithIOException(e);
         }
+        pageIndices.clear();
         idPositions.clear();
         actionSet.clear();
         super.stopRenderer();
@@ -322,8 +323,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         PageViewport pv = dd.getPageViewport();
         if (pv != null) {
             GoToXYAction action = getGoToActionForID(targetID, pv.getPageIndex());
-            NamedDestination namedDestination = new NamedDestination(targetID,
-                        action.createReference());
+            NamedDestination namedDestination = new NamedDestination(targetID, action);
             this.deferredDestinations.add(namedDestination);
         } else {
             //Warning already issued by AreaTreeHandler (debug level is sufficient)
@@ -367,7 +367,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         Bookmark b = new Bookmark(
                 bookmarkItem.getBookmarkTitle(),
                 bookmarkItem.showChildItems(),
-                (action != null ? action.createReference() : null));
+                action);
         for (int i = 0; i < bookmarkItem.getCount(); i++) {
             b.addChildBookmark(renderBookmarkItem(bookmarkItem.getSubData(i)));
         }
@@ -383,9 +383,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         GoToXYAction action = (GoToXYAction)actionSet.get(targetID);
         //GoToXYAction action = (GoToXYAction)idGoTos.get(targetID);
         if (action == null) {
+            if (pageIndex < 0) {
+                //pageIndex = page
+            }
             Point position = (Point)idPositions.get(targetID);
             // can the GoTo already be fully filled in?
-            if (position != null) {
+            if (pageIndex >= 0 && position != null) {
                 action = new GoToXYAction(targetID, pageIndex, position);
             } else {
                 // Not complete yet, can't use getPDFGoTo:
@@ -415,10 +418,16 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
 
     private void noteGoToPosition(GoToXYAction action, Point position) {
         action.setTargetLocation(position);
+        try {
+            getDocumentNavigationHandler().addResolvedAction(action);
+        } catch (IFException ife) {
+            handleIFException(ife);
+        }
         unfinishedGoTos.remove(action);
     }
 
     private void noteGoToPosition(GoToXYAction action, PageViewport pv, Point position) {
+        action.setPageIndex(pv.getPageIndex());
         noteGoToPosition(action, position);
     }
 
@@ -427,7 +436,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         Point position = new Point(relativeIPP, relativeBPP);
         tf.transform(position, position);
         idPositions.put(id, position);
-        // is there already a PDFGoTo waiting to be completed?
+        // is there already a GoTo action waiting to be completed?
         GoToXYAction action = (GoToXYAction)actionSet.get(id);
         if (action != null) {
             noteGoToPosition(action, pv, position);
@@ -439,9 +448,9 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
                              relativeIPP, relativeBPP, graphicContext.getTransform());
     }
 
-    protected void saveBlockPosIfTargetable(Block block) {
+    private void saveBlockPosIfTargetable(Block block) {
         String id = getTargetableID(block);
-        if (id != null) {
+        if (hasDocumentNavigation() && id != null) {
             // FIXME: Like elsewhere in the renderer code, absolute and relative
             //        directions are happily mixed here. This makes sure that the
             //        links point to the right location, but it is not correct.
@@ -458,7 +467,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
 
     private void saveInlinePosIfTargetable(InlineArea inlineArea) {
         String id = getTargetableID(inlineArea);
-        if (id != null) {
+        if (hasDocumentNavigation() && id != null) {
             int extraMarginBefore = 5000; // millipoints
             int ipp = currentIPPosition;
             int bpp = currentBPPosition + inlineArea.getOffset() - extraMarginBefore;
@@ -523,12 +532,18 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         return xmp;
     }
 
+    /** {@inheritDoc} */
+    public void preparePage(PageViewport page) {
+        super.preparePage(page);
+    }
+
     /** {@inheritDoc} */
     public void renderPage(PageViewport page) throws IOException, FOPException {
         if (log.isTraceEnabled()) {
             log.trace("renderPage() " + page);
         }
         try {
+            pageIndices.put(page.getKey(), new Integer(page.getPageIndex()));
             Rectangle2D viewArea = page.getViewArea();
             Dimension dim = new Dimension(
                     (int)Math.ceil(viewArea.getWidth()),
@@ -865,12 +880,12 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
         if (intLink != null) {
             linkTraitFound = true;
             String pvKey = intLink.getPVKey();
-
             String idRef = intLink.getIDRef();
             boolean pvKeyOK = pvKey != null && pvKey.length() > 0;
             boolean idRefOK = idRef != null && idRef.length() > 0;
             if (pvKeyOK && idRefOK) {
-                action = getGoToActionForID(idRef, this.currentPageViewport.getPageIndex());
+                Integer pageIndex = (Integer)pageIndices.get(pvKey);
+                action = getGoToActionForID(idRef, (pageIndex != null ? pageIndex.intValue() : -1));
             } else {
                 //Warnings already issued by AreaTreeHandler
             }
@@ -891,7 +906,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
 
         // warn if link trait found but not allowed, else create link
         if (linkTraitFound) {
-            Link link = new Link(action.createReference(), ipRect);
+            Link link = new Link(action, ipRect);
             this.deferredLinks.add(link);
         }
     }
@@ -987,7 +1002,7 @@ public class IFRenderer extends AbstractPathOrientedRenderer {
     protected void renderText(String s,
                            int[] letterAdjust,
                            Font font, AbstractTextArea parentArea) {
-        float fontSize = font.getFontSize() / 1000f;
+        //float fontSize = font.getFontSize() / 1000f;
 
         int l = s.length();
 
index c4fb0cb0d8817a66e63670566cea243eb549ae84..c54fe6407f0b6647df0a67901260901ddad7d050 100644 (file)
@@ -26,6 +26,7 @@ import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import org.w3c.dom.Document;
@@ -39,13 +40,16 @@ import org.apache.xmlgraphics.util.XMLizable;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.render.RenderingContext;
 import org.apache.fop.render.intermediate.extensions.AbstractAction;
+import org.apache.fop.render.intermediate.extensions.Bookmark;
 import org.apache.fop.render.intermediate.extensions.BookmarkTree;
+import org.apache.fop.render.intermediate.extensions.DocumentNavigationExtensionConstants;
 import org.apache.fop.render.intermediate.extensions.Link;
 import org.apache.fop.render.intermediate.extensions.NamedDestination;
 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.XMLConstants;
 import org.apache.fop.util.XMLUtil;
 
 /**
@@ -56,6 +60,9 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
 
     private IFDocumentHandler mimicHandler;
 
+    /** Holds the intermediate format state */
+    private IFState state;
+
     /**
      * Default constructor.
      */
@@ -93,10 +100,19 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
         return this;
     }
 
+    /**
+     * Tells this serializer to mimic the given document handler (mostly applies to the font set
+     * that is used during layout).
+     * @param targetHandler the document handler to mimic
+     */
     public void mimicDocumentHandler(IFDocumentHandler targetHandler) {
         this.mimicHandler = targetHandler;
     }
 
+    /**
+     * Returns the document handler that is being mimicked by this serializer.
+     * @return the mimicked document handler or null if no such document handler has been set
+     */
     public IFDocumentHandler getMimickedDocumentHandler() {
         return this.mimicHandler;
     }
@@ -126,6 +142,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
             handler.startDocument();
             handler.startPrefixMapping("", NAMESPACE);
             handler.startPrefixMapping(XLINK_PREFIX, XLINK_NAMESPACE);
+            handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX,
+                    DocumentNavigationExtensionConstants.NAMESPACE);
             handler.startElement(EL_DOCUMENT);
         } catch (SAXException e) {
             throw new IFException("SAX error in startDocument()", e);
@@ -173,6 +191,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
         try {
             handler.endElement(EL_DOCUMENT);
             handler.endDocument();
+            finishDocumentNavigation();
         } catch (SAXException e) {
             throw new IFException("SAX error in endDocument()", e);
         }
@@ -201,7 +220,8 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
     }
 
     /** {@inheritDoc} */
-    public void startPage(int index, String name, String pageMasterName, Dimension size) throws IFException {
+    public void startPage(int index, String name, String pageMasterName, Dimension size)
+                throws IFException {
         try {
             AttributesImpl atts = new AttributesImpl();
             addAttribute(atts, "index", Integer.toString(index));
@@ -237,6 +257,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
     public IFPainter startPageContent() throws IFException {
         try {
             handler.startElement(EL_PAGE_CONTENT);
+            this.state = IFState.create();
             return this;
         } catch (SAXException e) {
             throw new IFException("SAX error in startPageContent()", e);
@@ -246,6 +267,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
     /** {@inheritDoc} */
     public void endPageContent() throws IFException {
         try {
+            this.state = null;
             handler.endElement(EL_PAGE_CONTENT);
         } catch (SAXException e) {
             throw new IFException("SAX error in endPageContent()", e);
@@ -256,6 +278,7 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
     public void startPageTrailer() throws IFException {
         try {
             handler.startElement(EL_PAGE_TRAILER);
+            commitNavigation();
         } catch (SAXException e) {
             throw new IFException("SAX error in startPageTrailer()", e);
         }
@@ -510,25 +533,52 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
             Color color) throws IFException {
         try {
             AttributesImpl atts = new AttributesImpl();
+            boolean changed;
             if (family != null) {
-                addAttribute(atts, "family", family);
+                changed = !family.equals(state.getFontFamily());
+                if (changed) {
+                    state.setFontFamily(family);
+                    addAttribute(atts, "family", family);
+                }
             }
             if (style != null) {
-                addAttribute(atts, "style", style);
+                changed = !style.equals(state.getFontStyle());
+                if (changed) {
+                    state.setFontStyle(style);
+                    addAttribute(atts, "style", style);
+                }
             }
             if (weight != null) {
-                addAttribute(atts, "weight", weight.toString());
+                changed = (weight.intValue() != state.getFontWeight());
+                if (changed) {
+                    state.setFontWeight(weight.intValue());
+                    addAttribute(atts, "weight", weight.toString());
+                }
             }
             if (variant != null) {
-                addAttribute(atts, "variant", variant);
+                changed = !variant.equals(state.getFontVariant());
+                if (changed) {
+                    state.setFontVariant(variant);
+                    addAttribute(atts, "variant", variant);
+                }
             }
             if (size != null) {
-                addAttribute(atts, "size", size.toString());
+                changed = (size.intValue() != state.getFontSize());
+                if (changed) {
+                    state.setFontSize(size.intValue());
+                    addAttribute(atts, "size", size.toString());
+                }
             }
             if (color != null) {
-                addAttribute(atts, "color", toString(color));
+                changed = !color.equals(state.getTextColor());
+                if (changed) {
+                    state.setTextColor(color);
+                    addAttribute(atts, "color", toString(color));
+                }
+            }
+            if (atts.getLength() > 0) {
+                handler.element(EL_FONT, atts);
             }
-            handler.element(EL_FONT, atts);
         } catch (SAXException e) {
             throw new IFException("SAX error in setFont()", e);
         }
@@ -565,27 +615,112 @@ public class IFSerializer extends AbstractXMLWritingIFDocumentHandler
 
     // ---=== IFDocumentNavigationHandler ===---
 
+    private Map incompleteActions = new java.util.HashMap();
+    private List completeActions = new java.util.LinkedList();
+
+    private void noteAction(AbstractAction action) {
+        if (action == null) {
+            throw new NullPointerException("action must not be null");
+        }
+        if (!action.isComplete()) {
+            assert action.hasID();
+            incompleteActions.put(action.getID(), action);
+        }
+    }
+
     /** {@inheritDoc} */
     public void renderNamedDestination(NamedDestination destination) throws IFException {
-        renderXMLizable(destination);
+        noteAction(destination.getAction());
+
+        AttributesImpl atts = new AttributesImpl();
+        atts.addAttribute(null, "name", "name", XMLConstants.CDATA, destination.getName());
+        try {
+            handler.startElement(DocumentNavigationExtensionConstants.NAMED_DESTINATION, atts);
+            serializeXMLizable(destination.getAction());
+            handler.endElement(DocumentNavigationExtensionConstants.NAMED_DESTINATION);
+        } catch (SAXException e) {
+            throw new IFException("SAX error serializing named destination", e);
+        }
     }
 
     /** {@inheritDoc} */
     public void renderBookmarkTree(BookmarkTree tree) throws IFException {
-        renderXMLizable(tree);
+        AttributesImpl atts = new AttributesImpl();
+        try {
+            handler.startElement(DocumentNavigationExtensionConstants.BOOKMARK_TREE, atts);
+            Iterator iter = tree.getBookmarks().iterator();
+            while (iter.hasNext()) {
+                Bookmark b = (Bookmark)iter.next();
+                serializeBookmark(b);
+            }
+            handler.endElement(DocumentNavigationExtensionConstants.BOOKMARK_TREE);
+        } catch (SAXException e) {
+            throw new IFException("SAX error serializing bookmark tree", e);
+        }
     }
 
-    /** {@inheritDoc} */
-    public void addResolvedAction(AbstractAction action) throws IFException {
-        renderXMLizable(action);
+    private void serializeBookmark(Bookmark bookmark) throws SAXException, IFException {
+        noteAction(bookmark.getAction());
+
+        AttributesImpl atts = new AttributesImpl();
+        atts.addAttribute(null, "title", "title", XMLUtil.CDATA, bookmark.getTitle());
+        atts.addAttribute(null, "starting-state", "starting-state",
+                XMLUtil.CDATA, bookmark.isShown() ? "show" : "hide");
+        handler.startElement(DocumentNavigationExtensionConstants.BOOKMARK, atts);
+        serializeXMLizable(bookmark.getAction());
+        Iterator iter = bookmark.getChildBookmarks().iterator();
+        while (iter.hasNext()) {
+            Bookmark b = (Bookmark)iter.next();
+            serializeBookmark(b);
+        }
+        handler.endElement(DocumentNavigationExtensionConstants.BOOKMARK);
+
     }
 
     /** {@inheritDoc} */
     public void renderLink(Link link) throws IFException {
-        renderXMLizable(link);
+        noteAction(link.getAction());
+
+        AttributesImpl atts = new AttributesImpl();
+        atts.addAttribute(null, "rect", "rect",
+                XMLConstants.CDATA, IFUtil.toString(link.getTargetRect()));
+        try {
+            handler.startElement(DocumentNavigationExtensionConstants.LINK, atts);
+            serializeXMLizable(link.getAction());
+            handler.endElement(DocumentNavigationExtensionConstants.LINK);
+        } catch (SAXException e) {
+            throw new IFException("SAX error serializing link", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void addResolvedAction(AbstractAction action) throws IFException {
+        assert action.isComplete();
+        assert action.hasID();
+        AbstractAction noted = (AbstractAction)incompleteActions.get(action.getID());
+        if (noted != null) {
+            incompleteActions.remove(action.getID());
+            completeActions.add(action);
+        } else {
+            //ignore as it was already complete when it was first used.
+        }
+    }
+
+    private void commitNavigation() throws IFException {
+        Iterator iter = this.completeActions.iterator();
+        while (iter.hasNext()) {
+            AbstractAction action = (AbstractAction)iter.next();
+            iter.remove();
+            serializeXMLizable(action);
+        }
+        assert this.completeActions.size() == 0;
+    }
+
+    private void finishDocumentNavigation() {
+        assert this.incompleteActions.size() == 0 : "Still holding incomplete actions!";
     }
 
-    private void renderXMLizable(XMLizable object) throws IFException {
+    private void serializeXMLizable(XMLizable object) throws IFException {
         try {
             object.toSAX(handler);
         } catch (SAXException e) {
index f5bde16e1a22b37f6d91acbd08e1d196ef387dc3..f396fd09edc0b7ad09e754155d46d89b88ddf37e 100644 (file)
@@ -61,19 +61,12 @@ public abstract class AbstractAction implements XMLizable {
     public abstract boolean isSame(AbstractAction other);
 
     /**
-     * Indicates whether this action is a reference.
-     * @return true if this action is a reference, false for a normal action
+     * Indicates whether the action is complete, i.e has all the required information to be
+     * rendered in the target format.
+     * @return true if the action is complete
      */
-    public boolean isReference() {
-        return false;
-    }
-
-    /**
-     * Creates a reference to this action.
-     * @return the reference
-     */
-    public AbstractAction createReference() {
-        return new ReferencedAction(getID());
+    public boolean isComplete() {
+        return true;
     }
 
     /**
index df663baefc848cf965799447f12ecbabfae6a040..b980f1051389c523b71e4d9cdef4f87119110f8c 100644 (file)
@@ -22,21 +22,21 @@ package org.apache.fop.render.intermediate.extensions;
 import java.util.Iterator;
 import java.util.Map;
 
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-import org.apache.xmlgraphics.util.XMLizable;
-
 /**
  * This class manages actions and action references. Some action (like {@link GoToXYAction}s)
  * cannot be fully resolved at the time they are needed, so they are deferred. This class
  * helps manages the references and resolution.
  */
-public class ActionSet implements XMLizable {
+public class ActionSet {
 
     private int lastGeneratedID = 0;
     private Map actionRegistry = new java.util.HashMap();
 
+    /**
+     * Generates a new synthetic ID for an action.
+     * @param action the action
+     * @return the generated ID
+     */
     public synchronized String generateNewID(AbstractAction action) {
         this.lastGeneratedID++;
         String prefix = action.getIDPrefix();
@@ -46,10 +46,21 @@ public class ActionSet implements XMLizable {
         return prefix + this.lastGeneratedID;
     }
 
+    /**
+     * Returns the action with the given ID.
+     * @param id the ID
+     * @return the action or null if no action with this ID is stored
+     */
     public AbstractAction get(String id) {
         return (AbstractAction)this.actionRegistry.get(id);
     }
 
+    /**
+     * Puts an action into the set and returns the normalized instance (another one if the given
+     * one is equal to another.
+     * @param action the action
+     * @return the action instance that should be used in place of the given one
+     */
     public AbstractAction put(AbstractAction action) {
         if (!action.hasID()) {
             action.setID(generateNewID(action));
@@ -61,11 +72,14 @@ public class ActionSet implements XMLizable {
         return effAction;
     }
 
+    /**
+     * Clears the set.
+     */
     public void clear() {
         this.actionRegistry.clear();
     }
 
-    public AbstractAction normalize(AbstractAction action) {
+    private AbstractAction normalize(AbstractAction action) {
         Iterator iter = this.actionRegistry.values().iterator();
         while (iter.hasNext()) {
             AbstractAction a = (AbstractAction)iter.next();
@@ -76,12 +90,4 @@ public class ActionSet implements XMLizable {
         return action;
     }
 
-    public Iterator getActions() {
-        return this.actionRegistry.values().iterator();
-    }
-
-    public void toSAX(ContentHandler handler) throws SAXException {
-        // TODO Auto-generated method stub
-
-    }
 }
index b4c4bf192150d5d3755270b144ecc27bf7386ebe..5921ae6766f25b4a7c1c016be95d87a0f63d61ff 100644 (file)
 package org.apache.fop.render.intermediate.extensions;
 
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.xmlgraphics.util.XMLizable;
-
-import org.apache.fop.util.XMLConstants;
-import org.apache.fop.util.XMLUtil;
-
 /**
  * This class is a bookmark element for use in the intermediate format.
  */
-public class Bookmark implements XMLizable, DocumentNavigationExtensionConstants {
+public class Bookmark {
 
     private String title;
     private boolean show;
@@ -109,30 +99,4 @@ public class Bookmark implements XMLizable, DocumentNavigationExtensionConstants
         }
     }
 
-    /** {@inheritDoc} */
-    public void toSAX(ContentHandler handler) throws SAXException {
-        AttributesImpl atts = new AttributesImpl();
-        atts.addAttribute(null, "title", "title", XMLUtil.CDATA, getTitle());
-        atts.addAttribute(null, "starting-state", "starting-state",
-                XMLUtil.CDATA, isShown() ? "show" : "hide");
-        if (getAction().isReference()) {
-            atts.addAttribute(null, ACTION_REF, ACTION_REF,
-                    XMLConstants.CDATA, getAction().getID());
-        }
-        handler.startElement(BOOKMARK.getNamespaceURI(),
-                BOOKMARK.getLocalName(), BOOKMARK.getQName(), atts);
-        if (!getAction().isReference()) {
-            getAction().toSAX(handler);
-        }
-        if (this.childBookmarks != null) {
-            Iterator iter = this.childBookmarks.iterator();
-            while (iter.hasNext()) {
-                Bookmark b = (Bookmark)iter.next();
-                b.toSAX(handler);
-            }
-        }
-        handler.endElement(BOOKMARK.getNamespaceURI(),
-                BOOKMARK.getLocalName(), BOOKMARK.getQName());
-    }
-
 }
index 77e9726b302869fc9ffc06d6c7b985486202d5d8..e9fc6bf95407cd46f18bec98c9b60146cbe9ca82 100644 (file)
 package org.apache.fop.render.intermediate.extensions;
 
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.xmlgraphics.util.XMLizable;
-
 /**
  * This class is the root of the bookmark tree for use in the intermediate format.
  */
-public class BookmarkTree implements XMLizable, DocumentNavigationExtensionConstants {
+public class BookmarkTree {
 
     private List bookmarks = new java.util.ArrayList();
 
@@ -59,18 +52,4 @@ public class BookmarkTree implements XMLizable, DocumentNavigationExtensionConst
         return Collections.unmodifiableList(this.bookmarks);
     }
 
-    /** {@inheritDoc} */
-    public void toSAX(ContentHandler handler) throws SAXException {
-        AttributesImpl atts = new AttributesImpl();
-        handler.startElement(BOOKMARK_TREE.getNamespaceURI(),
-                BOOKMARK_TREE.getLocalName(), BOOKMARK_TREE.getQName(), atts);
-        Iterator iter = this.bookmarks.iterator();
-        while (iter.hasNext()) {
-            Bookmark b = (Bookmark)iter.next();
-            b.toSAX(handler);
-        }
-        handler.endElement(BOOKMARK_TREE.getNamespaceURI(),
-                BOOKMARK_TREE.getLocalName(), BOOKMARK_TREE.getQName());
-    }
-
 }
index 6c61f219e30bef388d191039efe338a6a8cf3412..b5e767bb2e8fa4d332f2395431ae0b9e40ecaa82 100644 (file)
@@ -28,25 +28,26 @@ import org.apache.fop.render.intermediate.IFConstants;
  */
 public interface DocumentNavigationExtensionConstants {
 
-    /** Namespace URI for the bookmark extension */
+    /** Namespace URI for the document navigation namespace */
     String NAMESPACE = IFConstants.NAMESPACE + "/document-navigation";
 
+    /** Default Namespace prefix for the document navigation namespace */
+    String PREFIX = "nav";
+
     /** the bookmark-tree element */
-    QName BOOKMARK_TREE = new QName(NAMESPACE, "bookmark-tree");
+    QName BOOKMARK_TREE = new QName(NAMESPACE, PREFIX, "bookmark-tree");
     /** the bookmark element */
-    QName BOOKMARK = new QName(NAMESPACE, "bookmark");
+    QName BOOKMARK = new QName(NAMESPACE, PREFIX, "bookmark");
 
     /** the named-destination element */
-    QName NAMED_DESTINATION = new QName(NAMESPACE, "named-destination");
+    QName NAMED_DESTINATION = new QName(NAMESPACE, PREFIX, "named-destination");
     /** the link element */
-    QName LINK = new QName(NAMESPACE, "link");
+    QName LINK = new QName(NAMESPACE, PREFIX, "link");
 
     /** the goto-xy element */
-    QName GOTO_XY = new QName(NAMESPACE, "goto-xy");
+    QName GOTO_XY = new QName(NAMESPACE, PREFIX, "goto-xy");
     /** the goto-uri element */
-    QName GOTO_URI = new QName(NAMESPACE, "goto-uri");
+    QName GOTO_URI = new QName(NAMESPACE, PREFIX, "goto-uri");
 
-    /** Attribute name for the action reference */
-    String ACTION_REF = "action-ref";
 
 }
index 4148b76f6657665fa3fc084a08272a9cfa6668b6..7efb82a1271165f9676176e16a92ac934fbf41a2 100644 (file)
@@ -32,20 +32,43 @@ import org.apache.fop.util.XMLUtil;
  */
 public class GoToXYAction extends AbstractAction implements DocumentNavigationExtensionConstants {
 
-    private int pageIndex;
+    private int pageIndex = -1;
     private Point targetLocation;
 
+    /**
+     * Creates a new instance with yet unknown location.
+     * @param id the identifier for this action
+     */
+    public GoToXYAction(String id) {
+        this(id, -1, null);
+    }
+
     /**
      * Creates a new instance.
-     * @param pageIndex the page index (0-based) of the target page
-     * @param targetLocation the absolute location on the page (coordinates in millipoints)
+     * @param id the identifier for this action
+     * @param pageIndex the index (0-based) of the target page, -1 if the page index is
+     *                  still unknown
+     * @param targetLocation the absolute location on the page (coordinates in millipoints),
+     *                  or null, if the position isn't known, yet
      */
     public GoToXYAction(String id, int pageIndex, Point targetLocation) {
         setID(id);
-        this.pageIndex = pageIndex;
+        if (pageIndex < 0 && targetLocation != null) {
+            throw new IllegalArgumentException(
+                    "Page index may not be null if target location is known!");
+        }
+        setPageIndex(pageIndex);
         setTargetLocation(targetLocation);
     }
 
+    /**
+     * Sets the index of the target page.
+     * @param pageIndex the index (0-based) of the target page
+     */
+    public void setPageIndex(int pageIndex) {
+        this.pageIndex = pageIndex;
+    }
+
     /**
      * Returns the page index of the target page.
      * @return the page index (0-based)
@@ -70,6 +93,11 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx
         this.targetLocation = location;
     }
 
+    /** {@inheritDoc} */
+    public boolean isComplete() {
+        return (getPageIndex() >= 0) && (getTargetLocation() != null);
+    }
+
     /** {@inheritDoc} */
     public boolean isSame(AbstractAction other) {
         if (other == null) {
@@ -82,7 +110,7 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx
         if (getPageIndex() != otherAction.getPageIndex()) {
             return false;
         }
-        if (getTargetLocation() == null && otherAction.getTargetLocation() != null) {
+        if (getTargetLocation() == null || otherAction.getTargetLocation() == null) {
             return false;
         }
         if (!getTargetLocation().equals(otherAction.getTargetLocation())) {
@@ -97,17 +125,27 @@ public class GoToXYAction extends AbstractAction implements DocumentNavigationEx
             setTargetLocation(new Point(0, 0));
         }
         AttributesImpl atts = new AttributesImpl();
-        if (hasID()) {
+        if (isComplete()) {
             atts.addAttribute(null, "id", "id", XMLUtil.CDATA, getID());
+            atts.addAttribute(null, "page-index", "page-index",
+                    XMLUtil.CDATA, Integer.toString(pageIndex));
+            atts.addAttribute(null, "x", "x", XMLUtil.CDATA, Integer.toString(targetLocation.x));
+            atts.addAttribute(null, "y", "y", XMLUtil.CDATA, Integer.toString(targetLocation.y));
+        } else {
+            atts.addAttribute(null, "idref", "idref", XMLUtil.CDATA, getID());
         }
-        atts.addAttribute(null, "page-index", "page-index",
-                XMLUtil.CDATA, Integer.toString(pageIndex));
-        atts.addAttribute(null, "x", "x", XMLUtil.CDATA, Integer.toString(targetLocation.x));
-        atts.addAttribute(null, "y", "y", XMLUtil.CDATA, Integer.toString(targetLocation.y));
         handler.startElement(GOTO_XY.getNamespaceURI(),
                 GOTO_XY.getLocalName(), GOTO_XY.getQName(), atts);
         handler.endElement(GOTO_XY.getNamespaceURI(),
                 GOTO_XY.getLocalName(), GOTO_XY.getQName());
     }
 
+    /** {@inheritDoc} */
+    public String toString() {
+        return "GoToXY: ID=" + getID()
+            + ", page=" + getPageIndex()
+            + ", loc=" + getTargetLocation() + ", "
+            + (isComplete() ? "complete" : "INCOMPLETE");
+    }
+
 }
index b54697ac4ba5dd9c80be4b063a4086daa17e951f..8e1558d5532fba7c913b29544b24d668f2015a38 100644 (file)
@@ -21,22 +21,10 @@ package org.apache.fop.render.intermediate.extensions;
 
 import java.awt.Rectangle;
 
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.xmlgraphics.util.XMLizable;
-
-import org.apache.fop.render.intermediate.IFUtil;
-import org.apache.fop.util.XMLConstants;
-
 /**
  * This class is a link element for use in the intermediate format.
  */
-public class Link implements XMLizable, DocumentNavigationExtensionConstants {
-
-    /** Attribute name for the target rectangle */
-    public static final String RECT = "rect";
+public class Link {
 
     private AbstractAction action;
     private Rectangle targetRect;
@@ -75,25 +63,4 @@ public class Link implements XMLizable, DocumentNavigationExtensionConstants {
         this.action = action;
     }
 
-    /** {@inheritDoc} */
-    public void toSAX(ContentHandler handler) throws SAXException {
-        if (getAction() == null) {
-            throw new IllegalStateException("Action has not been set");
-        }
-        AttributesImpl atts = new AttributesImpl();
-        atts.addAttribute(null, RECT, RECT,
-                XMLConstants.CDATA, IFUtil.toString(getTargetRect()));
-        if (getAction().isReference()) {
-            atts.addAttribute(null, ACTION_REF, ACTION_REF,
-                    XMLConstants.CDATA, getAction().getID());
-        }
-        handler.startElement(LINK.getNamespaceURI(),
-                LINK.getLocalName(), LINK.getQName(), atts);
-        if (!getAction().isReference()) {
-            getAction().toSAX(handler);
-        }
-        handler.endElement(LINK.getNamespaceURI(),
-                LINK.getLocalName(), LINK.getQName());
-    }
-
 }
index 21676832b0436856008134eccd8875f7b3840dbe..836d8abe09055b1e2d2ec3a4d8774adcb91556c6 100644 (file)
 
 package org.apache.fop.render.intermediate.extensions;
 
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.AttributesImpl;
-
-import org.apache.xmlgraphics.util.XMLizable;
-
-import org.apache.fop.util.XMLConstants;
 
 /**
  * This class is a named destination element for use in the intermediate format.
  */
-public class NamedDestination implements XMLizable, DocumentNavigationExtensionConstants {
-
-    /** Attribute name for the destination name */
-    public static final String NAME = "name";
+public class NamedDestination {
 
     private String name;
     private AbstractAction action;
@@ -72,24 +62,4 @@ public class NamedDestination implements XMLizable, DocumentNavigationExtensionC
         this.action = action;
     }
 
-    /** {@inheritDoc} */
-    public void toSAX(ContentHandler handler) throws SAXException {
-        if (getAction() == null) {
-            throw new IllegalStateException("Action has not been set");
-        }
-        AttributesImpl atts = new AttributesImpl();
-        atts.addAttribute(null, NAME, NAME, XMLConstants.CDATA, getName());
-        if (getAction().isReference()) {
-            atts.addAttribute(null, ACTION_REF, ACTION_REF,
-                    XMLConstants.CDATA, getAction().getID());
-        }
-        handler.startElement(NAMED_DESTINATION.getNamespaceURI(),
-                NAMED_DESTINATION.getLocalName(), NAMED_DESTINATION.getQName(), atts);
-        if (!getAction().isReference()) {
-            getAction().toSAX(handler);
-        }
-        handler.endElement(NAMED_DESTINATION.getNamespaceURI(),
-                NAMED_DESTINATION.getLocalName(), NAMED_DESTINATION.getQName());
-    }
-
 }
diff --git a/src/java/org/apache/fop/render/intermediate/extensions/ReferencedAction.java b/src/java/org/apache/fop/render/intermediate/extensions/ReferencedAction.java
deleted file mode 100644 (file)
index 20ec113..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.render.intermediate.extensions;
-
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-/**
- * Action class which references another action.
- */
-public class ReferencedAction extends AbstractAction
-            implements DocumentNavigationExtensionConstants {
-
-    /**
-     * Creates a new instance.
-     * @param id the ID
-     */
-    public ReferencedAction(String id) {
-        if (id == null || id.length() == 0) {
-            throw new NullPointerException("ID must not be set");
-        }
-        setID(id);
-    }
-
-    /** {@inheritDoc} */
-    public boolean isReference() {
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    public void toSAX(ContentHandler handler) throws SAXException {
-        //nop, handled by referencer
-    }
-
-    /** {@inheritDoc} */
-    public boolean isSame(AbstractAction other) {
-        throw new UnsupportedOperationException(
-                "isSame() may not be called on " + getClass().getName());
-    }
-
-}
index 6535be758a62cdd3ffe723838a78d8e056cc0b22..32ab2fa7a53f8b072735339be4d15287a2346fa4 100644 (file)
@@ -142,7 +142,6 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
     /** {@inheritDoc} */
     public void endDocument() throws IFException {
         try {
-            this.documentNavigationHandler.commit();
             pdfDoc.getResources().addFonts(pdfDoc, fontInfo);
             pdfDoc.outputTrailer(this.outputStream);
 
@@ -206,6 +205,7 @@ public class PDFDocumentHandler extends AbstractBinaryWritingIFDocumentHandler {
     /** {@inheritDoc} */
     public void endPage() throws IFException {
         try {
+            this.documentNavigationHandler.commit();
             this.pdfDoc.registerObject(generator.getStream());
             currentPage.setContents(generator.getStream());
             PDFAnnotList annots = currentPage.getAnnotations();
index a50fb85db28faab8b61ea28962f81225599e9829..d09957a39805546f9524f9653f7c3de743654960 100644 (file)
@@ -23,18 +23,17 @@ import java.awt.Rectangle;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.Iterator;
-import java.util.List;
+import java.util.Map;
 
 import org.apache.fop.pdf.PDFAction;
 import org.apache.fop.pdf.PDFDocument;
 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.PDFReference;
 import org.apache.fop.render.intermediate.IFDocumentNavigationHandler;
 import org.apache.fop.render.intermediate.IFException;
 import org.apache.fop.render.intermediate.extensions.AbstractAction;
-import org.apache.fop.render.intermediate.extensions.ActionSet;
 import org.apache.fop.render.intermediate.extensions.Bookmark;
 import org.apache.fop.render.intermediate.extensions.BookmarkTree;
 import org.apache.fop.render.intermediate.extensions.GoToXYAction;
@@ -50,8 +49,8 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
 
     private PDFDocumentHandler documentHandler;
 
-    private ActionSet actionSet = new ActionSet();
-    private List deferredLinks = new java.util.ArrayList();
+    private Map incompleteActions = new java.util.HashMap();
+    private Map completeActions = new java.util.HashMap();
 
     /**
      * Default constructor.
@@ -68,9 +67,9 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
 
     /** {@inheritDoc} */
     public void renderNamedDestination(NamedDestination destination) throws IFException {
-        PDFReference actionRef = getAction(destination.getAction());
+        PDFAction action = getAction(destination.getAction());
         getPDFDoc().getFactory().makeDestination(
-                destination.getName(), actionRef);
+                destination.getName(), action.makeReference());
     }
 
     /** {@inheritDoc} */
@@ -86,9 +85,9 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
         if (parent == null) {
             parent = getPDFDoc().getOutlineRoot();
         }
-        PDFReference actionRef = getAction(bookmark.getAction());
+        PDFAction action = getAction(bookmark.getAction());
         PDFOutline pdfOutline = getPDFDoc().getFactory().makeOutline(parent,
-            bookmark.getTitle(), actionRef.toString(), bookmark.isShown());
+            bookmark.getTitle(), action.makeReference().toString(), bookmark.isShown());
         Iterator iter = bookmark.getChildBookmarks().iterator();
         while (iter.hasNext()) {
             Bookmark b = (Bookmark)iter.next();
@@ -98,65 +97,85 @@ public class PDFDocumentNavigationHandler implements IFDocumentNavigationHandler
 
     /** {@inheritDoc} */
     public void renderLink(Link link) throws IFException {
-        this.deferredLinks.add(link);
+        Rectangle targetRect = link.getTargetRect();
+        int pageHeight = documentHandler.currentPageRef.getPageDimension().height;
+        Rectangle2D targetRect2D = new Rectangle2D.Double(
+                targetRect.getMinX() / 1000.0,
+                (pageHeight - targetRect.getMinY() - targetRect.getHeight()) / 1000.0,
+                targetRect.getWidth() / 1000.0,
+                targetRect.getHeight() / 1000.0);
+        PDFAction pdfAction = getAction(link.getAction());
+        //makeLink() currently needs a PDFAction and not a reference
+        //TODO Revisit when PDFLink is converted to a PDFDictionary
+        PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
+                targetRect2D, pdfAction);
+        documentHandler.currentPage.addAnnotation(pdfLink);
     }
 
     /**
      * Commits all pending elements to the PDF document.
      */
     public void commit() {
-        Iterator iter = this.deferredLinks.iterator();
-        while (iter.hasNext()) {
-            Link link = (Link)iter.next();
-            Rectangle targetRect = link.getTargetRect();
-            int pageHeight = documentHandler.currentPageRef.getPageDimension().height;
-            Rectangle2D targetRect2D = new Rectangle2D.Double(
-                    targetRect.getMinX() / 1000.0,
-                    (pageHeight - targetRect.getMinY()) / 1000.0,
-                    targetRect.getWidth() / 1000.0,
-                    targetRect.getHeight() / 1000.0);
-            PDFReference actionRef = getAction(link.getAction());
-            //makeLink() currently needs a PDFAction and not a reference
-            //TODO Revisit when PDFLink is converted to a PDFDictionary
-            PDFAction pdfAction = (PDFAction)actionRef.getObject();
-            PDFLink pdfLink = getPDFDoc().getFactory().makeLink(
-                    targetRect2D, pdfAction);
-            documentHandler.currentPage.addAnnotation(pdfLink);
-        }
     }
 
     /** {@inheritDoc} */
     public void addResolvedAction(AbstractAction action) throws IFException {
-        actionSet.put(action);
+        assert action.isComplete();
+        PDFAction pdfAction = (PDFAction)this.incompleteActions.remove(action.getID());
+        if (pdfAction == null) {
+            getAction(action);
+        } else if (pdfAction instanceof PDFGoTo) {
+            PDFGoTo pdfGoTo = (PDFGoTo)pdfAction;
+            updateTargetLocation(pdfGoTo, (GoToXYAction)action);
+        } else {
+            throw new UnsupportedOperationException(
+                    "Action type not supported: " + pdfAction.getClass().getName());
+        }
     }
 
-    private PDFReference getAction(AbstractAction action) {
-        if (action.isReference()) {
-            String id = action.getID();
-            action = actionSet.get(id);
-            if (action == null) {
-                throw new IllegalStateException("Action could not be resolved: " + id);
-            }
-        }
-        PDFFactory factory = getPDFDoc().getFactory();
-        if (action instanceof GoToXYAction) {
+    private PDFAction getAction(AbstractAction action) {
+        PDFAction pdfAction = (PDFAction)this.completeActions.get(action.getID());
+        if (pdfAction != null) {
+            return pdfAction;
+        } else if (action instanceof GoToXYAction) {
             GoToXYAction a = (GoToXYAction)action;
-            PageReference pageRef = this.documentHandler.getPageReference(a.getPageIndex());
-            //Convert target location from millipoints to points and adjust for different
-            //page origin
-            Point2D p2d = new Point2D.Double(
-                    a.getTargetLocation().x / 1000.0,
-                    (pageRef.getPageDimension().height - a.getTargetLocation().y) / 1000.0);
-            return factory.getPDFGoTo(pageRef.getPageRef().toString(), p2d).makeReference();
+            PDFGoTo pdfGoTo = new PDFGoTo(null);
+            getPDFDoc().assignObjectNumber(pdfGoTo);
+            if (action.isComplete()) {
+                updateTargetLocation(pdfGoTo, a);
+            } else {
+                this.incompleteActions.put(action.getID(), pdfGoTo);
+            }
+            return pdfGoTo;
         } else if (action instanceof URIAction) {
             URIAction u = (URIAction)action;
-            PDFAction pdfAction = factory.getExternalAction(u.getURI(), u.isNewWindow());
+            assert u.isComplete();
+            PDFFactory factory = getPDFDoc().getFactory();
+            pdfAction = factory.getExternalAction(u.getURI(), u.isNewWindow());
             getPDFDoc().registerObject(pdfAction);
-            return pdfAction.makeReference();
+            this.completeActions.put(action.getID(), pdfAction);
+            return pdfAction;
         } else {
             throw new UnsupportedOperationException("Unsupported action type: "
                     + action + " (" + action.getClass().getName() + ")");
         }
     }
 
+    private void updateTargetLocation(PDFGoTo pdfGoTo, GoToXYAction action) {
+        PageReference pageRef = this.documentHandler.getPageReference(action.getPageIndex());
+        //Convert target location from millipoints to points and adjust for different
+        //page origin
+        Point2D p2d = null;
+        p2d = new Point2D.Double(
+                action.getTargetLocation().x / 1000.0,
+                (pageRef.getPageDimension().height - action.getTargetLocation().y) / 1000.0);
+        String pdfPageRef = pageRef.getPageRef().toString();
+        pdfGoTo.setPageReference(pdfPageRef);
+        pdfGoTo.setPosition(p2d);
+
+        //Queue this object now that it's complete
+        getPDFDoc().addObject(pdfGoTo);
+        this.completeActions.put(action.getID(), pdfGoTo);
+    }
+
 }
index 11a7c8f6a1d3fdca575ca5449ad933f97f921bde..64fabbc8ab0e5156ac223e6554d58c75901016cd 100644 (file)
@@ -24,6 +24,8 @@ import org.xml.sax.ContentHandler;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 
+import org.apache.xmlgraphics.util.QName;
+
 /**
  * This class is a delegating SAX ContentHandler which has the purpose to provide a few handy
  * methods that make life easier when generating SAX events.
@@ -79,8 +81,27 @@ public class GenerationHelperContentHandler extends DelegatingContentHandler {
      * @throws SAXException if a SAX exception occurs
      */
     public void startElement(String localName) throws SAXException {
-        getDelegateContentHandler().startElement(getMainNamespace(), localName, localName,
-                EMPTY_ATTS);
+        startElement(localName, EMPTY_ATTS);
+    }
+
+    /**
+     * Convenience method to generate a startElement SAX event.
+     * @param qName the qualified name of the element
+     * @param atts the attributes
+     * @throws SAXException if a SAX exception occurs
+     */
+    public void startElement(QName qName, Attributes atts) throws SAXException {
+        getDelegateContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalName(),
+                qName.getQName(), atts);
+    }
+
+    /**
+     * Convenience method to generate a startElement SAX event.
+     * @param qName the qualified name of the element
+     * @throws SAXException if a SAX exception occurs
+     */
+    public void startElement(QName qName) throws SAXException {
+        startElement(qName, EMPTY_ATTS);
     }
 
     /**
@@ -93,7 +114,17 @@ public class GenerationHelperContentHandler extends DelegatingContentHandler {
     }
 
     /**
-     * Convenience method to generate an empty element.
+     * Convenience method to generate a startElement SAX event.
+     * @param qName the qualified name of the element
+     * @throws SAXException if a SAX exception occurs
+     */
+    public void endElement(QName qName) throws SAXException {
+        getDelegateContentHandler().endElement(qName.getNamespaceURI(), qName.getLocalName(),
+                qName.getQName());
+    }
+
+    /**
+     * Convenience method to generate an empty element with attributes.
      * @param localName the local name of the element
      * @param atts the attributes
      * @throws SAXException if a SAX exception occurs
@@ -103,4 +134,17 @@ public class GenerationHelperContentHandler extends DelegatingContentHandler {
         getDelegateContentHandler().endElement(getMainNamespace(), localName, localName);
     }
 
+    /**
+     * Convenience method to generate an empty element with attributes.
+     * @param qName the qualified name of the element
+     * @param atts the attributes
+     * @throws SAXException if a SAX exception occurs
+     */
+    public void element(QName qName, Attributes atts) throws SAXException {
+        getDelegateContentHandler().startElement(qName.getNamespaceURI(), qName.getLocalName(),
+                qName.getQName(), atts);
+        getDelegateContentHandler().endElement(qName.getNamespaceURI(), qName.getLocalName(),
+                qName.getQName());
+    }
+
 }