From cf02e02cc3e1d392b9abfd2eabba9054bb5f5ddc Mon Sep 17 00:00:00 2001 From: Keiron Liddle Date: Sat, 7 Sep 2002 08:58:07 +0000 Subject: [PATCH] implemented basic link with linking from pdf improved some resolving of references git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195155 13f79535-47bb-0310-9956-ffa450edef68 --- src/org/apache/fop/area/AreaTree.java | 254 +++++++++++++++--- src/org/apache/fop/area/Resolveable.java | 12 +- src/org/apache/fop/area/Trait.java | 2 +- .../apache/fop/area/inline/FilledArea.java | 11 +- .../apache/fop/area/inline/InlineArea.java | 11 +- .../apache/fop/area/inline/InlineParent.java | 10 +- .../fop/area/inline/UnresolvedPageNumber.java | 23 +- .../apache/fop/extensions/BookmarkData.java | 2 +- src/org/apache/fop/fo/flow/BasicLink.java | 93 ++++++- src/org/apache/fop/fo/flow/Leader.java | 22 +- .../fop/fo/flow/PageNumberCitation.java | 67 ++--- .../fop/layoutmgr/AbstractLayoutManager.java | 3 +- .../fop/layoutmgr/ContentLayoutManager.java | 11 +- .../fop/layoutmgr/FlowLayoutManager.java | 6 + .../InlineStackingLayoutManager.java | 9 +- .../apache/fop/layoutmgr/LayoutManager.java | 3 +- .../fop/layoutmgr/LeafNodeLayoutManager.java | 24 +- .../fop/layoutmgr/PageLayoutManager.java | 7 +- src/org/apache/fop/pdf/PDFDocument.java | 6 +- src/org/apache/fop/pdf/PDFLink.java | 12 +- .../apache/fop/render/pdf/PDFRenderer.java | 118 ++++++-- 21 files changed, 534 insertions(+), 172 deletions(-) diff --git a/src/org/apache/fop/area/AreaTree.java b/src/org/apache/fop/area/AreaTree.java index a67d8411e..5958b6390 100644 --- a/src/org/apache/fop/area/AreaTree.java +++ b/src/org/apache/fop/area/AreaTree.java @@ -1,6 +1,6 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ @@ -34,45 +34,74 @@ import java.util.Iterator; public class AreaTree { // allows for different models to deal with adding/rendering // in different situations - AreaTreeModel model; + private AreaTreeModel model; // hashmap of arraylists containing pages with id area - HashMap idLocations = new HashMap(); + private HashMap idLocations = new HashMap(); // list of id's yet to be resolved and arraylists of pages - HashMap resolve = new HashMap(); - ArrayList treeExtensions = new ArrayList(); - + private HashMap resolve = new HashMap(); + private ArrayList treeExtensions = new ArrayList(); + + /** + * Create a render pages area tree model. + * @param rend the renderer that will be used + * @return RenderPagesModel the new area tree model + */ public RenderPagesModel createRenderPagesModel(Renderer rend) { return new RenderPagesModel(rend); } + /** + * Create a new store pages model. + * @return StorePagesModel the new model + */ public static StorePagesModel createStorePagesModel() { return new StorePagesModel(); } + /** + * Set the tree model to use for this area tree. + * The different models can have different behaviour + * when pages area added and other changes. + * @param m the area tree model + */ public void setTreeModel(AreaTreeModel m) { model = m; } + /** + * Start a new page sequence. + * This signals that a new page sequence has started in the document. + * @param title the title of the new page sequence or null if no title + */ public void startPageSequence(Title title) { model.startPageSequence(title); } + /** + * Add a new page to the area tree. + * @param page the page to add + */ public void addPage(PageViewport page) { model.addPage(page); } + /** + * Add an id reference pointing to a page viewport. + * @param id the id of the reference + * @param pv the page viewport that contains the id reference + */ public void addIDRef(String id, PageViewport pv) { - ArrayList list = (ArrayList)idLocations.get(id); - if(list == null) { + List list = (List)idLocations.get(id); + if (list == null) { list = new ArrayList(); idLocations.put(id, list); } list.add(pv); - ArrayList todo = (ArrayList)resolve.get(id); - if(todo != null) { - for(int count = 0; count < todo.size(); count++) { + List todo = (List)resolve.get(id); + if (todo != null) { + for (int count = 0; count < todo.size(); count++) { Resolveable res = (Resolveable)todo.get(count); res.resolve(id, list); } @@ -80,47 +109,80 @@ public class AreaTree { } } + /** + * Get the list of id references for an id. + * @param id the id to lookup + * @return the list of id references. + */ + public List getIDReferences(String id) { + return (List)idLocations.get(id); + } + + /** + * Add an unresolved object with a given id. + * @param id the id reference that needs resolving + * @param res the Resolveable object to resolve + */ public void addUnresolvedID(String id, Resolveable res) { ArrayList todo = (ArrayList)resolve.get(id); - if(todo == null) { + if (todo == null) { todo = new ArrayList(); resolve.put(id, todo); } todo.add(res); } + /** + * Add a tree extension. + * This checks if the extension is resolveable and attempts + * to resolve or add the resolveable ids for later resolution. + * @param ext the tree extension to add. + */ public void addTreeExtension(TreeExt ext) { treeExtensions.add(ext); - if(ext.isResolveable()) { + if (ext.isResolveable()) { Resolveable res = (Resolveable)ext; String[] ids = res.getIDs(); - for(int count = 0; count < ids.length; count++) { - if(idLocations.containsKey(ids[count])) { + for (int count = 0; count < ids.length; count++) { + if (idLocations.containsKey(ids[count])) { res.resolve(ids[count], (ArrayList)idLocations.get(ids[count])); } else { ArrayList todo = (ArrayList)resolve.get(ids[count]); - if(todo == null) { + if (todo == null) { todo = new ArrayList(); resolve.put(ids[count], todo); } todo.add(ext); } } + } else { + handleTreeExtension(ext, TreeExt.IMMEDIATELY); } } + /** + * Handle a tree extension. + * This sends the extension to the model for handling. + * @param ext the tree extension to handle + * @param when when the extension should be handled by the model + */ public void handleTreeExtension(TreeExt ext, int when) { // queue tree extension according to the when model.addExtension(ext, when); } + /** + * Signal end of document. + * This indicates that the document is complete and any unresolved + * reference can be dealt with. + */ public void endDocument() { - for(Iterator iter = resolve.keySet().iterator(); iter.hasNext(); ) { + for (Iterator iter = resolve.keySet().iterator(); iter.hasNext();) { String id = (String)iter.next(); ArrayList list = (ArrayList)resolve.get(id); - for(int count = 0; count < list.size(); count++) { + for (int count = 0; count < list.size(); count++) { Resolveable res = (Resolveable)list.get(count); - if(!res.isResolved()) { + if (!res.isResolved()) { res.resolve(id, null); } } @@ -128,24 +190,59 @@ public class AreaTree { model.endDocument(); } - // this is the model for the area tree object - public static abstract class AreaTreeModel { + /** + * This is the model for the area tree object. + * The model implementation can handle the page sequence, + * page and extensions. + */ + public abstract static class AreaTreeModel { + /** + * Start a page sequence on this model. + * @param title the title of the new page sequence + */ public abstract void startPageSequence(Title title); + + /** + * Add a page to this moel. + * @param page the page to add to the model. + */ public abstract void addPage(PageViewport page); + + /** + * Add an extension to this model. + * @param ext the extension to add + * @param when when the extension should be handled + */ public abstract void addExtension(TreeExt ext, int when); + + /** + * Signal the end of the document for any processing. + */ public abstract void endDocument(); } - // this class stores all the pages in the document - // for interactive agents + /** + * This class stores all the pages in the document + * for interactive agents. + * The pages are stored and can be retrieved in any order. + */ public static class StorePagesModel extends AreaTreeModel { - ArrayList pageSequence = null; - ArrayList titles = new ArrayList(); - ArrayList currSequence; - ArrayList extensions = new ArrayList(); - - public StorePagesModel() {} + private ArrayList pageSequence = null; + private ArrayList titles = new ArrayList(); + private ArrayList currSequence; + private ArrayList extensions = new ArrayList(); + + /** + * Create a new store pages model + */ + public StorePagesModel() { + } + /** + * Start a new page sequence. + * This creates a new list for the pages in the new page sequence. + * @param title the title of the page sequence. + */ public void startPageSequence(Title title) { titles.add(title); if (pageSequence == null) { @@ -155,28 +252,59 @@ public class AreaTree { pageSequence.add(currSequence); } + /** + * Add a page. + * @param page the page to add to the current page sequence + */ public void addPage(PageViewport page) { currSequence.add(page); } + /** + * Get the page sequence count. + * @return the number of page sequences in the document. + */ public int getPageSequenceCount() { return pageSequence.size(); } + /** + * Get the title for a page sequence. + * @param count the page sequence count + * @return the title of the page sequence + */ public Title getTitle(int count) { return (Title) titles.get(count); } + /** + * Get the page count. + * @param seq the page sequence to count. + * @return returns the number of pages in a page sequence + */ public int getPageCount(int seq) { ArrayList sequence = (ArrayList) pageSequence.get(seq); return sequence.size(); } + /** + * Get the page for a position in the document. + * @param seq the page sequence number + * @param count the page count in the sequence + * @return the PageViewport for the particular page + */ public PageViewport getPage(int seq, int count) { ArrayList sequence = (ArrayList) pageSequence.get(seq); return (PageViewport) sequence.get(count); } + /** + * Add an extension to the store page model. + * The extension is stored so that it can be retrieved in the + * appropriate position. + * @param ext the extension to add + * @param when when the extension should be handled + */ public void addExtension(TreeExt ext, int when) { int seq, page; switch(when) { @@ -192,42 +320,78 @@ public class AreaTree { extensions.add(ext); } + /** + * Get the list of extensions that apply at a particular + * position in the document. + * @param seq the page sequence number + * @param count the page count in the sequence + * @return the list of extensions + */ public List getExtensions(int seq, int count) { return null; } + /** + * Get the end of document extensions for this stroe pages model. + * @return the list of end extensions + */ public List getEndExtensions() { return extensions; } + /** + * End document, do nothing. + */ public void endDocument() { } } - // this uses the store pages model to store the pages - // each page is either rendered if ready or prepared - // for later rendering + /** + * This uses the store pages model to store the pages + * each page is either rendered if ready or prepared + * for later rendering. + * Once a page is rendered it is cleared to release the + * contents but the PageViewport is retained. + */ public static class RenderPagesModel extends StorePagesModel { - Renderer renderer; - ArrayList prepared = new ArrayList(); - ArrayList pendingExt = new ArrayList(); - ArrayList endDocExt = new ArrayList(); - + private Renderer renderer; + private ArrayList prepared = new ArrayList(); + private ArrayList pendingExt = new ArrayList(); + private ArrayList endDocExt = new ArrayList(); + + /** + * Create a new render pages model with the given renderer. + * @param rend the renderer to render pages to + */ public RenderPagesModel(Renderer rend) { renderer = rend; } + /** + * Start a new page sequence. + * This tells the renderer that a new page sequence has + * started with the given title. + * @param title the title of the new page sequence + */ public void startPageSequence(Title title) { super.startPageSequence(title); renderer.startPageSequence(title); } + /** + * Add a page to the render page model. + * If the page is finished it can be rendered immediately. + * If the page needs resolving then if the renderer supports + * out of order rendering it can prepare the page. Otherwise + * the page is added to a queue. + * @param page the page to add to the model + */ public void addPage(PageViewport page) { super.addPage(page); // if page finished try { renderer.renderPage(page); - } catch(Exception e) { + } catch (Exception e) { // use error handler to handle this FOP or IO Exception } page.clear(); @@ -240,6 +404,15 @@ public class AreaTree { prepared.add(page); } + /** + * Add an extension to this model. + * If handle immediately then send directly to the renderer. + * The after page ones are handled after the next page is added. + * End of document extensions are added to a list to be + * handled at the end. + * @param ext the extension + * @param when when to render the extension + */ public void addExtension(TreeExt ext, int when) { switch(when) { case TreeExt.IMMEDIATELY: @@ -255,12 +428,15 @@ public class AreaTree { } private void renderExtensions(ArrayList list) { - for(int count = 0; count < list.size(); count++) { + for (int count = 0; count < list.size(); count++) { TreeExt ext = (TreeExt)list.get(count); renderer.renderExtension(ext); } } + /** + * End the document. Render any end document extensions. + */ public void endDocument() { renderExtensions(endDocExt); } diff --git a/src/org/apache/fop/area/Resolveable.java b/src/org/apache/fop/area/Resolveable.java index d0eeabc51..c40fc5329 100644 --- a/src/org/apache/fop/area/Resolveable.java +++ b/src/org/apache/fop/area/Resolveable.java @@ -7,9 +7,15 @@ package org.apache.fop.area; -import java.util.ArrayList; +import java.util.List; +import java.io.Serializable; -public interface Resolveable { +/** + * Resolveable Interface. + * Classes that implement this can be resolved when + * an id is added to the area tree. + */ +public interface Resolveable extends Serializable { public boolean isResolved(); @@ -22,5 +28,5 @@ public interface Resolveable { * @param pages the list of pages with the id area * may be null if not found */ - public void resolve(String id, ArrayList pages); + public void resolve(String id, List pages); } diff --git a/src/org/apache/fop/area/Trait.java b/src/org/apache/fop/area/Trait.java index 8aecae835..06fcd75f4 100644 --- a/src/org/apache/fop/area/Trait.java +++ b/src/org/apache/fop/area/Trait.java @@ -57,7 +57,7 @@ public class Trait implements Serializable { s_hmTraitInfo.put(ID_LINK, new TraitInfo("id-link", String.class)); s_hmTraitInfo.put(INTERNAL_LINK, - new TraitInfo("internal-link", String.class)); + new TraitInfo("internal-link", PageViewport.class)); s_hmTraitInfo.put(EXTERNAL_LINK, new TraitInfo("external-link", String.class)); s_hmTraitInfo.put(FONT_NAME, diff --git a/src/org/apache/fop/area/inline/FilledArea.java b/src/org/apache/fop/area/inline/FilledArea.java index c12973539..b92c3e997 100644 --- a/src/org/apache/fop/area/inline/FilledArea.java +++ b/src/org/apache/fop/area/inline/FilledArea.java @@ -20,8 +20,7 @@ import java.util.ArrayList; * this inline parent. */ public class FilledArea extends InlineParent { - MinOptMax alloc; - int unitWidth; + private int unitWidth; public FilledArea() { } @@ -30,14 +29,6 @@ public class FilledArea extends InlineParent { unitWidth = w; } - public void setAllocationIPD(MinOptMax all) { - alloc = all; - } - - public MinOptMax getAllocationIPD() { - return alloc; - } - public List getChildAreas() { int units = (int)(getWidth() / unitWidth); ArrayList newList = new ArrayList(); diff --git a/src/org/apache/fop/area/inline/InlineArea.java b/src/org/apache/fop/area/inline/InlineArea.java index 0b38a54a6..58cd68871 100644 --- a/src/org/apache/fop/area/inline/InlineArea.java +++ b/src/org/apache/fop/area/inline/InlineArea.java @@ -1,6 +1,6 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * Copyright (C) 2002 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ @@ -14,7 +14,6 @@ import org.apache.fop.render.Renderer; import org.apache.fop.traits.BorderProps; import org.apache.fop.fo.properties.VerticalAlign; -import java.util.List; import java.util.ArrayList; /** @@ -29,8 +28,8 @@ public class InlineArea extends Area { int height; protected int contentIPD = 0; - // position within the line area, either top or baseline - int verticalPosition = VerticalAlign.BASELINE; + // offset position from top of parent area + int verticalPosition = 0; // store properties in array list, need better solution ArrayList props = null; @@ -53,6 +52,10 @@ public class InlineArea extends Area { this.contentIPD = ipd; } + public int getIPD() { + return this.contentIPD; + } + public void increaseIPD(int ipd) { this.contentIPD += ipd; } diff --git a/src/org/apache/fop/area/inline/InlineParent.java b/src/org/apache/fop/area/inline/InlineParent.java index cc733b9ad..d1f66124a 100644 --- a/src/org/apache/fop/area/inline/InlineParent.java +++ b/src/org/apache/fop/area/inline/InlineParent.java @@ -14,18 +14,24 @@ import org.apache.fop.render.Renderer; import java.util.List; import java.util.ArrayList; -// this is an inline area that can have other inlines as children +/** + * Inline parent area. + * This is an inline area that can have other inlines as children. + */ public class InlineParent extends InlineArea { protected ArrayList inlines = new ArrayList(); public InlineParent() { } + /** + * Render this area. + * @param renderer the renderer to render this area in + */ public void render(Renderer renderer) { renderer.renderInlineParent(this); } - /** * Override generic Area method. */ diff --git a/src/org/apache/fop/area/inline/UnresolvedPageNumber.java b/src/org/apache/fop/area/inline/UnresolvedPageNumber.java index 98a17de0b..952949506 100644 --- a/src/org/apache/fop/area/inline/UnresolvedPageNumber.java +++ b/src/org/apache/fop/area/inline/UnresolvedPageNumber.java @@ -9,12 +9,13 @@ package org.apache.fop.area.inline; import org.apache.fop.area.PageViewport; import org.apache.fop.area.Resolveable; +import org.apache.fop.area.Trait; -import java.util.ArrayList; +import java.util.List; public class UnresolvedPageNumber extends Word implements Resolveable { - boolean resolved = false; - String pageRefId; + private boolean resolved = false; + private String pageRefId; public UnresolvedPageNumber(String id) { pageRefId = id; @@ -25,11 +26,19 @@ public class UnresolvedPageNumber extends Word implements Resolveable { return new String[] {pageRefId}; } - public void resolve(String id, ArrayList pages) { + public void resolve(String id, List pages) { resolved = true; - PageViewport page = (PageViewport)pages.get(0); - String str = page.getPageNumber(); - word = str; + if(pages != null) { + PageViewport page = (PageViewport)pages.get(0); + String str = page.getPageNumber(); + word = str; + + // update ipd + String name = (String) getTrait(Trait.FONT_NAME); + int size = ((Integer) getTrait(Trait.FONT_SIZE)).intValue(); + //FontMetric metrics = fontInfo.getMetricsFor(name); + //FontState fs = new FontState(name, metrics, size); + } } public boolean isResolved() { diff --git a/src/org/apache/fop/extensions/BookmarkData.java b/src/org/apache/fop/extensions/BookmarkData.java index 69847851a..87a29cb77 100644 --- a/src/org/apache/fop/extensions/BookmarkData.java +++ b/src/org/apache/fop/extensions/BookmarkData.java @@ -91,7 +91,7 @@ public class BookmarkData implements Resolveable, TreeExt { return (String[])idRefs.keySet().toArray(new String[] {}); } - public void resolve(String id, ArrayList pages) { + public void resolve(String id, List pages) { if(!id.equals(idRef)) { BookmarkData bd = (BookmarkData)idRefs.get(id); idRefs.remove(id); diff --git a/src/org/apache/fop/fo/flow/BasicLink.java b/src/org/apache/fop/fo/flow/BasicLink.java index fb66c9733..6f7dfdfed 100644 --- a/src/org/apache/fop/fo/flow/BasicLink.java +++ b/src/org/apache/fop/fo/flow/BasicLink.java @@ -13,13 +13,24 @@ import org.apache.fop.apps.FOPException; import org.apache.fop.fo.properties.*; import org.apache.fop.layout.*; import org.apache.fop.datatypes.ColorType; +import org.apache.fop.area.inline.InlineParent; +import org.apache.fop.area.Trait; +import org.apache.fop.area.Resolveable; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Area; +import org.apache.fop.layoutmgr.InlineStackingLayoutManager; +import org.apache.fop.layoutmgr.LMiter; +import org.apache.fop.layoutmgr.LayoutManager; // Java import java.util.Enumeration; import java.awt.Rectangle; import java.util.List; +import java.util.ArrayList; public class BasicLink extends Inline { + String link = null; + boolean external = false; public BasicLink(FONode parent) { super(parent); @@ -27,7 +38,32 @@ public class BasicLink extends Inline { // add start and end properties for the link public void addLayoutManager(List lms) { - super.addLayoutManager(lms); + setup(); + lms.add(new InlineStackingLayoutManager(this, + new LMiter(children.listIterator())) { + protected InlineParent createArea() { + InlineParent area = super.createArea(); + setupLinkArea(parentLM, area); + return area; + } + }); + } + + protected void setupLinkArea(LayoutManager parentLM, InlineParent area) { + if(link == null) { + return; + } + if(external) { + area.addTrait(Trait.EXTERNAL_LINK, link); + } else { + PageViewport page = parentLM.resolveRefID(link); + if(page != null) { + area.addTrait(Trait.INTERNAL_LINK, page); + } else { + LinkResolver res = new LinkResolver(link, area); + parentLM.addUnresolvedArea(link, res); + } + } } public void setup() { @@ -55,20 +91,61 @@ public class BasicLink extends Inline { // this.properties.get("baseline-shift"); // this.properties.get("destination-place-offset"); // this.properties.get("dominant-baseline"); - // this.properties.get("external-destination"); + String ext = properties.get("external-destination").getString(); setupID(); - // this.properties.get("indicate-destination"); - // this.properties.get("internal-destination"); + // this.properties.get("indicate-destination"); + String internal = properties.get("internal-destination").getString(); + if(ext.length() > 0) { + link = ext; + external = true; + } else if(internal.length() > 0) { + link = internal; + } else { + getLogger().error("basic-link requires an internal or external destination"); + } // this.properties.get("keep-together"); // this.properties.get("keep-with-next"); // this.properties.get("keep-with-previous"); // this.properties.get("line-height"); // this.properties.get("line-height-shift-adjustment"); - // this.properties.get("show-destination"); - // this.properties.get("target-processing-context"); - // this.properties.get("target-presentation-context"); - // this.properties.get("target-stylesheet"); + // this.properties.get("show-destination"); + // this.properties.get("target-processing-context"); + // this.properties.get("target-presentation-context"); + // this.properties.get("target-stylesheet"); + + } + + protected static class LinkResolver implements Resolveable { + private boolean resolved = false; + private String idRef; + // NOTE: there will be a problem with serialization + private Area area; + + public LinkResolver(String id, Area a) { + idRef = id; + area = a; + } + + public boolean isResolved() { + return resolved; + } + + public String[] getIDs() { + return new String[] {idRef}; + } + + /** + * Resolve by removing the id link and replacing with + * an internal link. + */ + public void resolve(String id, List pages) { + if(idRef.equals(id) && pages != null) { + PageViewport page = (PageViewport)pages.get(0); + area.addTrait(Trait.INTERNAL_LINK, page); + } + } } } + diff --git a/src/org/apache/fop/fo/flow/Leader.java b/src/org/apache/fop/fo/flow/Leader.java index 0a84fc928..be4274cc3 100644 --- a/src/org/apache/fop/fo/flow/Leader.java +++ b/src/org/apache/fop/fo/flow/Leader.java @@ -55,25 +55,21 @@ public class Leader extends FObjMixed { public void addLayoutManager(List list) { LeafNodeLayoutManager lm = new LeafNodeLayoutManager(this) { public InlineArea get(LayoutContext context) { - int refIPD = context.getRefIPD(); - return getInlineArea(refIPD); + return getInlineArea(); + } + + protected MinOptMax getAllocationIPD(int refIPD) { + return getAllocIPD(refIPD); } }; lm.setAlignment(properties.get("leader-alignment").getEnum()); list.add(lm); } - protected InlineArea getInlineArea(int refIPD) { + protected InlineArea getInlineArea() { if(leaderArea == null) { createLeaderArea(); } - MinOptMax alloc = getAllocationIPD(refIPD); - if(leaderArea instanceof Stretch) { - ((Stretch)leaderArea).setAllocationIPD(alloc); - } else if(leaderArea instanceof FilledArea) { - ((FilledArea)leaderArea).setAllocationIPD(alloc); - } - leaderArea.setWidth(alloc.opt); return leaderArea; } @@ -88,9 +84,7 @@ public class Leader extends FObjMixed { leaderArea = leader; } else if (leaderPattern == LeaderPattern.SPACE) { - Space space = new Space(); - - leaderArea = space; + leaderArea = new Space(); } else if(leaderPattern == LeaderPattern.DOTS) { Word w = new Word(); char dot = '.'; // userAgent.getLeaderDotChar(); @@ -226,7 +220,7 @@ public class Leader extends FObjMixed { } - protected MinOptMax getAllocationIPD(int ipd) { + protected MinOptMax getAllocIPD(int ipd) { // length of the leader int opt = getLength("leader-length.optimum", ipd); int min = getLength("leader-length.minimum", ipd); diff --git a/src/org/apache/fop/fo/flow/PageNumberCitation.java b/src/org/apache/fop/fo/flow/PageNumberCitation.java index 7d343cb2e..3093dfc37 100644 --- a/src/org/apache/fop/fo/flow/PageNumberCitation.java +++ b/src/org/apache/fop/fo/flow/PageNumberCitation.java @@ -16,6 +16,7 @@ import org.apache.fop.layout.*; import org.apache.fop.apps.FOPException; import org.apache.fop.layoutmgr.LeafNodeLayoutManager; import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.PageViewport; import org.apache.fop.util.CharUtilities; import org.apache.fop.apps.StructureHandler; import org.apache.fop.layoutmgr.LayoutContext; @@ -67,52 +68,54 @@ public class PageNumberCitation extends FObj { } public void addAreas(PositionIterator posIter, - LayoutContext context) { + LayoutContext context) { super.addAreas(posIter, context); - if(unresolved) { - parentLM.addUnresolvedArea(refId, (Resolveable)inline); + if (unresolved) { + parentLM.addUnresolvedArea(refId, + (Resolveable) inline); } } } ); } - // is id can be resolved then simply return a word, otherwise + // if id can be resolved then simply return a word, otherwise // return a resolveable area private InlineArea getInlineArea(LayoutManager parentLM) { if (refId.equals("")) { getLogger().error("page-number-citation must contain \"ref-id\""); return null; } - String str = parentLM.resolveRefID(refId); - if(str != null) { - // get page string from parent, build area - Word word = new Word(); - inline = word; - int width = getStringWidth(str); - word.setWord(str); - inline.setIPD(width); - inline.setHeight(fontState.getAscender() - - fontState.getDescender()); - inline.setOffset(fontState.getAscender()); - - inline.addTrait(Trait.FONT_NAME, fontState.getFontName()); - inline.addTrait(Trait.FONT_SIZE, - new Integer(fontState.getFontSize())); + PageViewport page = parentLM.resolveRefID(refId); + if (page != null) { + String str = page.getPageNumber(); + // get page string from parent, build area + Word word = new Word(); + inline = word; + int width = getStringWidth(str); + word.setWord(str); + inline.setIPD(width); + inline.setHeight(fontState.getAscender() - + fontState.getDescender()); + inline.setOffset(fontState.getAscender()); + + inline.addTrait(Trait.FONT_NAME, fontState.getFontName()); + inline.addTrait(Trait.FONT_SIZE, + new Integer(fontState.getFontSize())); + unresolved = false; } else { - unresolved = true; - inline = new UnresolvedPageNumber(refId); - str = "MMM"; // reserve three spaces for page number - int width = getStringWidth(str); - inline.setIPD(width); - inline.setHeight(fontState.getAscender() - - fontState.getDescender()); - inline.setOffset(fontState.getAscender()); - - inline.addTrait(Trait.FONT_NAME, fontState.getFontName()); - inline.addTrait(Trait.FONT_SIZE, - new Integer(fontState.getFontSize())); - + unresolved = true; + inline = new UnresolvedPageNumber(refId); + String str = "MMM"; // reserve three spaces for page number + int width = getStringWidth(str); + inline.setIPD(width); + inline.setHeight(fontState.getAscender() - + fontState.getDescender()); + inline.setOffset(fontState.getAscender()); + + inline.addTrait(Trait.FONT_NAME, fontState.getFontName()); + inline.addTrait(Trait.FONT_SIZE, + new Integer(fontState.getFontSize())); } return inline; } diff --git a/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java index d18b7c186..519eaade8 100644 --- a/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/AbstractLayoutManager.java @@ -11,6 +11,7 @@ import org.apache.fop.fo.FObj; import org.apache.fop.fo.FONode; import org.apache.fop.area.Area; import org.apache.fop.area.Resolveable; +import org.apache.fop.area.PageViewport; import org.apache.fop.fo.PropertyManager; import java.util.ListIterator; @@ -260,7 +261,7 @@ public abstract class AbstractLayoutManager implements LayoutManager { return parentLM.getCurrentPageNumber(); } - public String resolveRefID(String ref) { + public PageViewport resolveRefID(String ref) { return parentLM.resolveRefID(ref); } diff --git a/src/org/apache/fop/layoutmgr/ContentLayoutManager.java b/src/org/apache/fop/layoutmgr/ContentLayoutManager.java index 7c39a6206..27204bedc 100644 --- a/src/org/apache/fop/layoutmgr/ContentLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/ContentLayoutManager.java @@ -11,6 +11,7 @@ package org.apache.fop.layoutmgr; import org.apache.fop.area.Area; import org.apache.fop.area.MinOptMax; import org.apache.fop.area.Resolveable; +import org.apache.fop.area.PageViewport; import java.util.ArrayList; @@ -22,6 +23,7 @@ import java.util.ArrayList; public class ContentLayoutManager implements LayoutManager { Area holder; int stackSize; + LayoutManager parentLM; public ContentLayoutManager(Area area) { holder = area; @@ -76,6 +78,7 @@ public class ContentLayoutManager implements LayoutManager { } public void setParentLM(LayoutManager lm) { + parentLM = lm; } public boolean canBreakBefore(LayoutContext lc) { @@ -107,17 +110,19 @@ public class ContentLayoutManager implements LayoutManager { } public String getCurrentPageNumber() { - return ""; + return parentLM.getCurrentPageNumber(); } - public String resolveRefID(String ref) { - return null; + public PageViewport resolveRefID(String ref) { + return parentLM.resolveRefID(ref);; } public void addIDToPage(String id) { + parentLM.addIDToPage(id); } public void addUnresolvedArea(String id, Resolveable res) { + parentLM.addUnresolvedArea(id, res); } } diff --git a/src/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/org/apache/fop/layoutmgr/FlowLayoutManager.java index f7dce7825..4b12bd385 100644 --- a/src/org/apache/fop/layoutmgr/FlowLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/FlowLayoutManager.java @@ -42,6 +42,12 @@ public class FlowLayoutManager extends BlockStackingLayoutManager { MinOptMax stackSize = new MinOptMax(); while ((curLM = getChildLM()) != null) { + if(curLM.generatesInlineAreas()) { + // problem + curLM.setFinished(true); + continue; + } + // Make break positions and return page break // Set up a LayoutContext MinOptMax bpd = context.getStackLimit(); diff --git a/src/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java b/src/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java index dcc6414c8..8616353e5 100644 --- a/src/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java @@ -378,6 +378,10 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager { } *****/ + protected InlineParent createArea() { + return new InlineParent(); + } + /** * Generate and add areas to parent area. * Set size of each area. @@ -388,7 +392,10 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager { */ public void addAreas(PositionIterator parentIter, LayoutContext context) { - setCurrentArea(new InlineParent()); + InlineParent parent = createArea(); + parent.setHeight(context.getLineHeight()); + parent.setOffset(0); + setCurrentArea(parent); setChildContext(new LayoutContext(context)); // Store current value diff --git a/src/org/apache/fop/layoutmgr/LayoutManager.java b/src/org/apache/fop/layoutmgr/LayoutManager.java index 455dc8f0c..cac65a075 100644 --- a/src/org/apache/fop/layoutmgr/LayoutManager.java +++ b/src/org/apache/fop/layoutmgr/LayoutManager.java @@ -10,6 +10,7 @@ package org.apache.fop.layoutmgr; import org.apache.fop.area.Area; import org.apache.fop.area.Resolveable; +import org.apache.fop.area.PageViewport; /** * The interface for all LayoutManagers. @@ -65,7 +66,7 @@ public interface LayoutManager { public String getCurrentPageNumber(); - public String resolveRefID(String ref); + public PageViewport resolveRefID(String ref); public void addIDToPage(String id); diff --git a/src/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java b/src/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java index a0f7ea24f..59ebf978e 100644 --- a/src/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java @@ -23,6 +23,7 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { private InlineArea curArea = null; private int alignment; private int lead; + private MinOptMax ipd; public LeafNodeLayoutManager(FObj fobj) { super(fobj); @@ -76,7 +77,8 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { BreakPoss.CAN_BREAK_AFTER | BreakPoss.CAN_BREAK_BEFORE | BreakPoss.ISFIRST | BreakPoss.ISLAST); - bp.setStackingSize(curArea.getAllocationIPD()); + ipd = getAllocationIPD(context.getRefIPD()); + bp.setStackingSize(ipd); bp.setNonStackingSize(curArea.getAllocationBPD()); bp.setTrailingSpace(new SpaceSpecifier(false)); @@ -101,6 +103,10 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { return bp; } + protected MinOptMax getAllocationIPD(int refIPD) { + return new MinOptMax(curArea.getIPD()); + } + public void resetPosition(Position resetPos) { // only reset if setting null, start again if(resetPos == null) { @@ -113,6 +119,15 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { addID(); + offsetArea(context); + widthAdjustArea(context); + + while (posIter.hasNext()) { + posIter.next(); + } + } + + protected void offsetArea(LayoutContext context) { int bpd = curArea.getHeight(); switch(alignment) { case VerticalAlign.MIDDLE: @@ -129,9 +144,10 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { curArea.setOffset(context.getBaseline() - bpd); break; } + } + protected void widthAdjustArea(LayoutContext context) { double dAdjust = context.getIPDAdjust(); - MinOptMax ipd = curArea.getAllocationIPD(); int width = ipd.opt; if(dAdjust < 0) { width = (int)(width + dAdjust * (ipd.opt - ipd.min)); @@ -139,10 +155,6 @@ public class LeafNodeLayoutManager extends AbstractLayoutManager { width = (int)(width + dAdjust * (ipd.max - ipd.opt)); } curArea.setWidth(width); - - while (posIter.hasNext()) { - posIter.next(); - } } public boolean canBreakBefore(LayoutContext context) { diff --git a/src/org/apache/fop/layoutmgr/PageLayoutManager.java b/src/org/apache/fop/layoutmgr/PageLayoutManager.java index 00e9b6c3e..14fee48ff 100644 --- a/src/org/apache/fop/layoutmgr/PageLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/PageLayoutManager.java @@ -138,7 +138,11 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable return "" + pageCount; } - public String resolveRefID(String ref) { + public PageViewport resolveRefID(String ref) { + List list = areaTree.getIDReferences(ref); + if(list != null && list.size() > 0) { + return (PageViewport)list.get(0); + } return null; } @@ -155,6 +159,7 @@ public class PageLayoutManager extends AbstractLayoutManager implements Runnable public void addUnresolvedArea(String id, Resolveable res) { // add unresolved to tree + // should really add to the page viewport so it can serialize areaTree.addUnresolvedID(id, res); } diff --git a/src/org/apache/fop/pdf/PDFDocument.java b/src/org/apache/fop/pdf/PDFDocument.java index d04b2d0d1..ffdd3de32 100644 --- a/src/org/apache/fop/pdf/PDFDocument.java +++ b/src/org/apache/fop/pdf/PDFDocument.java @@ -21,7 +21,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; /** * class representing a PDF document. @@ -1174,7 +1174,7 @@ public class PDFDocument { * @param linkType the link type * @return the PDFLink object created */ - public PDFLink makeLink(Rectangle rect, String destination, + public PDFLink makeLink(Rectangle2D rect, String destination, int linkType) { PDFLink linkObject; @@ -1216,7 +1216,7 @@ public class PDFDocument { this.trailerObjects.add(object); } - public PDFLink makeLink(Rectangle rect, String page, String dest) { + public PDFLink makeLink(Rectangle2D rect, String page, String dest) { PDFLink link = new PDFLink(++this.objectcount, rect); this.objects.add(link); diff --git a/src/org/apache/fop/pdf/PDFLink.java b/src/org/apache/fop/pdf/PDFLink.java index e1e20b661..0c39fed24 100644 --- a/src/org/apache/fop/pdf/PDFLink.java +++ b/src/org/apache/fop/pdf/PDFLink.java @@ -8,7 +8,7 @@ package org.apache.fop.pdf; // Java -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; /** * class representing an /Annot object of /Subtype /Link @@ -30,14 +30,14 @@ public class PDFLink extends PDFObject { * @param number the object's number * @param producer the application producing the PDF */ - public PDFLink(int number, Rectangle r) { + public PDFLink(int number, Rectangle2D r) { /* generic creation of PDF object */ super(number); - this.ulx = r.x; - this.uly = r.y; - this.brx = r.x + r.width; - this.bry = r.y - r.height; + 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 } diff --git a/src/org/apache/fop/render/pdf/PDFRenderer.java b/src/org/apache/fop/render/pdf/PDFRenderer.java index 1d91c40ba..3cda99199 100644 --- a/src/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/org/apache/fop/render/pdf/PDFRenderer.java @@ -1,6 +1,6 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * Copyright (C) 2001-2002 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. */ @@ -35,6 +35,7 @@ import org.w3c.dom.Document; import java.io.IOException; import java.io.OutputStream; import java.awt.geom.Rectangle2D; +import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.util.HashMap; import java.util.List; @@ -178,7 +179,7 @@ public class PDFRenderer extends PrintRenderer { public void renderExtension(TreeExt ext) { // render bookmark extension - if(ext instanceof BookmarkData) { + if (ext instanceof BookmarkData) { renderRootExtensions((BookmarkData)ext); } } @@ -209,7 +210,7 @@ public class PDFRenderer extends PrintRenderer { } public void startPageSequence(Title seqTitle) { - if(seqTitle != null) { + if (seqTitle != null) { String str = convertTitleToString(seqTitle); PDFInfo info = this.pdfDoc.getInfo(); info.setTitle(str); @@ -326,7 +327,7 @@ public class PDFRenderer extends PrintRenderer { currentStream.add("ET\n"); - if(bv.getClip()) { + if (bv.getClip()) { Rectangle2D rect = bv.getBounds(); currentStream.add("q\n"); @@ -354,7 +355,7 @@ public class PDFRenderer extends PrintRenderer { Rectangle2D rect = bv.getBounds(); - if(ctm != null) { + if (ctm != null) { currentIPPosition = 0; currentBPPosition = 0; @@ -362,16 +363,16 @@ public class PDFRenderer extends PrintRenderer { double[] vals = ctm.toArray(); boolean aclock = vals[2] == 1.0; - if(vals[2] == 1.0) { + if (vals[2] == 1.0) { ctm = ctm.translate(-saveBP - rect.getHeight(), -saveIP); - } else if(vals[0] == -1.0) { + } else if (vals[0] == -1.0) { ctm = ctm.translate(-saveIP - rect.getWidth(), -saveBP - rect.getHeight()); } else { ctm = ctm.translate(saveBP, saveIP - rect.getWidth()); } } - if(bv.getClip()) { + if (bv.getClip()) { currentStream.add("q\n"); float x = (float)rect.getX() / 1000f; float y = (float)rect.getY() / 1000f; @@ -380,24 +381,24 @@ public class PDFRenderer extends PrintRenderer { clip(x, y, width, height); } - if(ctm != null) { + if (ctm != null) { startVParea(ctm); } renderBlocks(children); - if(ctm != null) { + if (ctm != null) { endVParea(); } if (bv.getClip()) { currentStream.add("Q\n"); } - if(ctm != null) { + if (ctm != null) { currentStream.add("BT\n"); } // clip if necessary - if(rect != null) { + if (rect != null) { currentIPPosition = saveIP; currentBPPosition = saveBP; currentBPPosition += (int)(rect.getHeight()); @@ -405,6 +406,15 @@ public class PDFRenderer extends PrintRenderer { } } + /** + * Clip an area. + * write a clipping operation given coordinates in the current + * transform. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the area + * @param height the height of the area + */ protected void clip(float x, float y, float width, float height) { currentStream.add(x + " " + y + " m\n"); currentStream.add((x + width) + " " + y + " l\n"); @@ -420,6 +430,45 @@ public class PDFRenderer extends PrintRenderer { closeText(); } + /** + * Render inline parent area. + * For pdf this handles the inline parent area traits such as + * links, border, background. + * @param ip the inline parent area + */ + public void renderInlineParent(InlineParent ip) { + Object tr = ip.getTrait(Trait.INTERNAL_LINK); + boolean internal = false; + String dest = null; + if (tr == null) { + dest = (String)ip.getTrait(Trait.EXTERNAL_LINK); + } else { + PageViewport pv = (PageViewport)tr; + dest = (String)pageReferences.get(pv); + internal = true; + } + if (dest != null) { + float start = currentBlockIPPosition; + float top = (ip.getOffset() + currentBPPosition) / 1000f; + float height = ip.getHeight() / 1000f; + super.renderInlineParent(ip); + float width = (currentBlockIPPosition - start) / 1000f; + start = start / 1000f; + // add link to pdf document + Rectangle2D rect = new Rectangle2D.Float(start, top, width, height); + // transform rect to absolute coords + AffineTransform transform = currentState.getTransform(); + rect = transform.createTransformedShape(rect).getBounds(); + rect = new Rectangle2D.Double(rect.getX(), rect.getY() + rect.getHeight(), rect.getWidth(), rect.getHeight()); + + int type = internal ? PDFLink.INTERNAL : PDFLink.EXTERNAL; + PDFLink pdflink = pdfDoc.makeLink(rect, dest, type); + currentPage.addAnnotation(pdflink); + } else { + super.renderInlineParent(ip); + } + } + public void renderCharacter(Character ch) { super.renderCharacter(ch); @@ -453,8 +502,8 @@ public class PDFRenderer extends PrintRenderer { if (!textOpen || bl != prevWordY) { closeText(); - pdf.append("1 0 0 -1 " + (rx / 1000f) + " " + - (bl / 1000f) + " Tm [" + startText); + pdf.append("1 0 0 -1 " + (rx / 1000f) + " " + + (bl / 1000f) + " Tm [" + startText); prevWordY = bl; textOpen = true; } else { @@ -467,8 +516,8 @@ public class PDFRenderer extends PrintRenderer { if (emDiff < -33000) { closeText(); - pdf.append("1 0 0 1 " + (rx / 1000f) + " " + - (bl / 1000f) + " Tm [" + startText); + pdf.append("1 0 0 1 " + (rx / 1000f) + " " + + (bl / 1000f) + " Tm [" + startText); textOpen = true; } else { pdf.append(Float.toString(emDiff)); @@ -553,10 +602,11 @@ public class PDFRenderer extends PrintRenderer { (int) uniBytes[i]; String hexString = Integer.toHexString(b); - if (hexString.length() == 1) + if (hexString.length() == 1) { buf = buf.append("0" + hexString); - else + } else { buf = buf.append(hexString); + } } return buf.toString(); } @@ -608,8 +658,8 @@ public class PDFRenderer extends PrintRenderer { } private void updateFont(String name, int size, StringBuffer pdf) { - if ((!name.equals(this.currentFontName)) || - (size != this.currentFontSize)) { + if ((!name.equals(this.currentFontName)) + || (size != this.currentFontSize)) { closeText(); this.currentFontName = name; @@ -693,16 +743,16 @@ public class PDFRenderer extends PrintRenderer { try { this.pdfDoc.output(ostream); } catch (IOException ioe) { - + // ioexception will be caught later } } protected void placeImage(int x, int y, int w, int h, int xobj) { - currentStream.add("q\n" + ((float) w) + " 0 0 " + - ((float) - h) + " " + - (((float) currentBlockIPPosition) / 1000f + x) + " " + - (((float)(currentBPPosition + 1000 * h)) / 1000f + - y) + " cm\n" + "/Im" + xobj + " Do\nQ\n"); + currentStream.add("q\n" + ((float) w) + " 0 0 " + + ((float) - h) + " " + + (((float) currentBlockIPPosition) / 1000f + x) + " " + + (((float)(currentBPPosition + 1000 * h)) / 1000f + + y) + " cm\n" + "/Im" + xobj + " Do\nQ\n"); } @@ -738,6 +788,11 @@ public class PDFRenderer extends PrintRenderer { } + /** + * Render an inline viewport. + * This renders an inline viewport by clipping if necessary. + * @param viewport the viewport to handle + */ public void renderViewport(Viewport viewport) { closeText(); currentStream.add("ET\n"); @@ -758,6 +813,11 @@ public class PDFRenderer extends PrintRenderer { currentStream.add("BT\n"); } + /** + * Render leader area. + * This renders a leader area which is an area with a rule. + * @param area the leader area to render + */ public void renderLeader(Leader area) { closeText(); currentStream.add("ET\n"); @@ -783,14 +843,14 @@ public class PDFRenderer extends PrintRenderer { float startx = ((float) currentBlockIPPosition) / 1000f; float starty = ((currentBPPosition + area.getOffset()) / 1000f); float endx = (currentBlockIPPosition + area.getWidth()) / 1000f; - if(!alt) { + if (!alt) { currentStream.add(area.getRuleThickness() / 1000f + " w\n"); currentStream.add(startx + " " + starty + " m\n"); currentStream.add(endx + " " + starty + " l\n"); currentStream.add("S\n"); } else { - if(style == RuleStyle.DOUBLE) { + if (style == RuleStyle.DOUBLE) { float third = area.getRuleThickness() / 3000f; currentStream.add(third + " w\n"); currentStream.add(startx + " " + starty + " m\n"); @@ -810,7 +870,7 @@ public class PDFRenderer extends PrintRenderer { currentStream.add(startx + " " + (starty + 2 * half) + " l\n"); currentStream.add("h\n"); currentStream.add("f\n"); - if(style == RuleStyle.GROOVE) { + if (style == RuleStyle.GROOVE) { currentStream.add("0 g\n"); currentStream.add(startx + " " + starty + " m\n"); currentStream.add(endx + " " + starty + " l\n"); -- 2.39.5