From: Simon Pepping Date: Tue, 21 Dec 2004 11:28:05 +0000 (+0000) Subject: Implemented cloning and reparenting of the subtree under a marker to X-Git-Tag: Root_Temp_KnuthStylePageBreaking~303 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=d5d34b4c18eb338c8d077df37fbba698dc878975;p=xmlgraphics-fop.git Implemented cloning and reparenting of the subtree under a marker to the retrieving retrieve-marker. The FO nodes are cloned. The new subtree is attached to the RetrieveMarker object. The property lists are not cloned. The subtree of property lists is attached to the property list of the RetrieveMarker object. This is only needed for the binding of the FO nodes. After that a subsequent retrieve-marker may reparent the property lists. Removed Marker's reference to its property list. In Marker.endOfNode() the parent of the property lists of the direct children of marker is reset to null. FOText nodes are not mapped to the Marker's property list in Marker. This allows the Marker's property list and its ancestors to be GC'ed. FOText nodes use the parent FO node's property list or the RetrieveMarker's property list for binding. TODO: Block.handleWhiteSpace is not applied to text in retrieve-marker. TODO: White space treatment around retrieve-marker is incorrect. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198204 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index d128454be..ed8959813 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -37,7 +37,7 @@ import org.apache.fop.util.CharUtilities; /** * base class for nodes in the XML tree */ -public abstract class FONode { +public abstract class FONode implements Cloneable { protected static String FO_URI = FOElementMapping.URI; @@ -62,6 +62,34 @@ public abstract class FONode { this.parent = parent; } + /** + * Perform a shallow cloning operation, + * set its parent, and optionally clean the list of child nodes + * @param parent the intended parent of the clone + * @param removeChildren if true, clean the list of child nodes + * @return the cloned FO node + */ + public FONode clone(FONode parent, boolean removeChildren) + throws FOPException { + FONode foNode = (FONode) clone(); + foNode.parent = parent; + parent.addChildNode(foNode); + return foNode; + } + + /** + * Perform a shallow cloning operation + * + * @see java.lang.Object#clone() + * @return the cloned object + */ + protected Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { } + return null; + } + /** * Set the location information for this element * @param locator the org.xml.sax.Locator object diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 87f989c02..7820f9acd 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -85,6 +85,18 @@ public class FObj extends FONode implements Constants { } } + /** + * @see org.apache.fop.fo.FONode#clone(FONode, boolean) + */ + public FONode clone(FONode parent, boolean removeChildren) + throws FOPException { + FObj fobj = (FObj) super.clone(parent, removeChildren); + if (removeChildren) { + fobj.childNodes = null; + } + return fobj; + } + /** * @see org.apache.fop.fo.FONode#processNode */ diff --git a/src/java/org/apache/fop/fo/flow/Marker.java b/src/java/org/apache/fop/fo/flow/Marker.java index 8ac8b1345..b8395d074 100644 --- a/src/java/org/apache/fop/fo/flow/Marker.java +++ b/src/java/org/apache/fop/fo/flow/Marker.java @@ -45,9 +45,8 @@ public class Marker extends FObjMixed { private String markerClassName; // End of property values - private MarkerPropertyList propertyList; private PropertyListMaker savePropertyListMaker; - private HashMap children = new HashMap(); + private HashMap descPLists = new HashMap(); /** * Create a marker fo. @@ -65,27 +64,16 @@ public class Marker extends FObjMixed { } /** - * Rebind the marker and all the children using the specified - * parentPropertyList which comes from the fo:retrieve-marker element. - * @param parentPropertyList The property list from fo:retrieve-marker. + * retrieve the property list of foNode + * @param foNode the FO node whose property list is requested + * @return the MarkerPropertyList of foNode */ - public void rebind(PropertyList parentPropertyList) throws FOPException { - // Set a new parent property list and bind all the children again. - propertyList.setParentPropertyList(parentPropertyList); - for (Iterator i = children.keySet().iterator(); i.hasNext(); ) { - FONode child = (FONode) i.next(); - PropertyList childList = (PropertyList) children.get(child); - if (child instanceof FObj) { - ((FObj) child).bind(childList); - } else if (child instanceof FOText) { - ((FOText) child).bind(childList); - } - } + protected MarkerPropertyList getPList(FONode foNode) { + return (MarkerPropertyList) descPLists.get(foNode); } protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws FOPException { - propertyList = new MarkerPropertyList(this, parent); - return propertyList; + return new MarkerPropertyList(this, parent); } protected void startOfNode() { @@ -95,23 +83,28 @@ public class Marker extends FObjMixed { foEventHandler.setPropertyListMaker(new PropertyListMaker() { public PropertyList make(FObj fobj, PropertyList parentPropertyList) { PropertyList pList = new MarkerPropertyList(fobj, parentPropertyList); - children.put(fobj, pList); + descPLists.put(fobj, pList); return pList; } }); } - protected void addChildNode(FONode child) throws FOPException { - if (!children.containsKey(child)) { - children.put(child, propertyList); - } - super.addChildNode(child); - } - protected void endOfNode() { // Pop the MarkerPropertyList maker. getFOEventHandler().setPropertyListMaker(savePropertyListMaker); savePropertyListMaker = null; + // unparent the child property lists + Iterator iter = getChildNodes(); + if (iter != null) { + while (iter.hasNext()) { + FONode child = (FONode) iter.next(); + MarkerPropertyList pList + = (MarkerPropertyList) descPLists.get(child); + if (pList != null) { + pList.setParentPropertyList(null); + } + } + } } /** @@ -131,17 +124,9 @@ public class Marker extends FObjMixed { /** * @see org.apache.fop.fo.FONode#addLayoutManager(List) - * @todo remove null check when vCN() & endOfNode() implemented */ public void addLayoutManager(List list) { - ListIterator baseIter = getChildNodes(); - if (baseIter == null) { - return; - } - while (baseIter.hasNext()) { - FONode child = (FONode) baseIter.next(); - child.addLayoutManager(list); - } + // no layout manager } /** diff --git a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java index 2ac17aaf1..f9d5fd95b 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java @@ -18,6 +18,12 @@ package org.apache.fop.fo.flow; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.List; + import org.xml.sax.Locator; import org.apache.commons.logging.Log; @@ -25,6 +31,8 @@ import org.apache.commons.logging.Log; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FOEventHandler; import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FOText; +import org.apache.fop.fo.FObj; import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.StaticPropertyList; @@ -72,6 +80,21 @@ public class RetrieveMarker extends FObjMixed { invalidChildError(loc, nsURI, localName); } + /** + * @see org.apache.fop.fo.FONode#addLayoutManager(List) + * @todo remove null check when vCN() & endOfNode() implemented + */ + public void addLayoutManager(List list) { + Iterator baseIter = getChildNodes(); + if (baseIter == null) { + return; + } + while (baseIter.hasNext()) { + FONode child = (FONode) baseIter.next(); + child.addLayoutManager(list); + } + } + protected PropertyList createPropertyList(PropertyList parent, FOEventHandler foEventHandler) throws FOPException { // TODO: A special RetrieveMarkerPropertyList would be more memory @@ -106,10 +129,96 @@ public class RetrieveMarker extends FObjMixed { return retrieveBoundary; } + /** + * Clone the FO nodes in the parent iterator, + * attach the new nodes to the new parent, + * and map the new nodes to the existing property lists. + * FOText nodes are also in the new map, with a null value. + * Clone the subtree by a recursive call to this method. + * @param parentIter the iterator over the children of the old parent + * @param newParent the new parent for the cloned nodes + * @param marker the marker that contains the old property list mapping + * @param descPLists the map of the new nodes to property lists + */ + private void cloneSubtree(Iterator parentIter, FONode newParent, + Marker marker, Map descPLists) + throws FOPException { + if (parentIter == null) return; + while (parentIter.hasNext()) { + FONode child = (FONode) parentIter.next(); + FONode newChild = child.clone(newParent, true); + descPLists.put(newChild, marker.getPList(child)); + cloneSubtree(child.getChildNodes(), newChild, marker, descPLists); + } + } + + /** + * Clone the subtree of marker, + * attach the new subtree to this node, + * reparent the property lists of the direct children + * to the property list of this node. + * @param marker the marker that is to be cloned + * @param descPLists the map of the new nodes to property lists + */ + private void cloneFromMarker(Marker marker, Map descPLists) + throws FOPException { + // release child nodes from a possible earlier layout + childNodes = new ArrayList(); + Iterator markerIter = marker.getChildNodes(); + cloneSubtree(markerIter, this, marker, descPLists); + // reparent the property lists of the direct children + for (Iterator iter = getChildNodes(); iter.hasNext(); ) { + FONode child = (FONode) iter.next(); + Marker.MarkerPropertyList pList + = (Marker.MarkerPropertyList) descPLists.get(child); + if (pList != null) { + pList.setParentPropertyList(propertyList); + } + } + } + + /** + * Bind the new nodes to the property values in this context + * @param descPLists the map of the new nodes to property lists + */ + private void bindChildren(Map descPLists) throws FOPException { + for (Iterator i = descPLists.keySet().iterator(); i.hasNext(); ) { + FONode desc = (FONode) i.next(); + PropertyList descPList; + if (desc instanceof FObj) { + descPList = (PropertyList) descPLists.get(desc); + ((FObj) desc).bind(descPList); + } else if (desc instanceof FOText) { + descPList = (PropertyList) descPLists.get(desc.getParent()); + if (descPList == null) { + descPList = propertyList; + } + ((FOText) desc).bind(descPList); + } + } + } + + /** + * Clone the subtree of marker + * and bind the nodes to the property values in this context + * @param marker the marker that is to be cloned + */ public void bindMarker(Marker marker) { // assert(marker != null); + // catch empty marker + if (marker.getChildNodes() == null) { + return; + } + HashMap descPLists = new HashMap(); + try { + cloneFromMarker(marker, descPLists); + } catch (FOPException exc) { + Log log = getLogger(); + log.error("fo:retrieve-marker unable to clone subtree of fo:marker", exc); + return; + } try { - marker.rebind(getPropertyList()); + bindChildren(descPLists); } catch (FOPException exc) { Log log = getLogger(); log.error("fo:retrieve-marker unable to rebind property values", exc); diff --git a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java index 8906e024e..09edee56f 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java @@ -382,7 +382,7 @@ public abstract class AbstractLayoutManager implements LayoutManager, Constants continue; } rm.bindMarker(marker); - foNode = marker; + foNode = rm; } foNode.addLayoutManager(newLMs); }