Browse Source

added support for markers in fo tree

bit of a cleanup


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195539 13f79535-47bb-0310-9956-ffa450edef68
pull/30/head
Keiron Liddle 21 years ago
parent
commit
67117725a0

+ 3
- 2
src/org/apache/fop/apps/StructureHandler.java View File

@@ -8,6 +8,7 @@
package org.apache.fop.apps;

// Java
import java.util.Set;
import java.util.HashSet;

// Avalon
@@ -31,12 +32,12 @@ public class StructureHandler extends AbstractLogEnabled {
The current set of id's in the FO tree
This is used so we know if the FO tree contains duplicates
*/
private HashSet idReferences = new HashSet();
private Set idReferences = new HashSet();

public StructureHandler() {
}

public HashSet getIDReferences() {
public Set getIDReferences() {
return idReferences;
}


+ 2
- 2
src/org/apache/fop/datatypes/LengthBase.java View File

@@ -70,9 +70,9 @@ public class LengthBase implements PercentBase {
return propertyList.get("font-size").getLength().mvalue();
case INH_FONTSIZE:
return propertyList.getInherited("font-size").getLength().mvalue();
case CONTAINING_BOX:
//case CONTAINING_BOX:
// depends on property?? inline-progression vs block-progression
return parentFO.getContentWidth();
//return parentFO.getContentWidth();
case CONTAINING_REFAREA: // example: start-indent, end-indent
{
//FONode fo;

+ 13
- 2
src/org/apache/fop/fo/FONode.java View File

@@ -106,11 +106,22 @@ public abstract class FONode {
* this FObj.
*/
public ListIterator getChildren(FONode childNode) {
return null;
return null;
}

public CharIterator charIterator() {
return new OneCharIterator(CharUtilities.CODE_EOT);
return new OneCharIterator(CharUtilities.CODE_EOT);
}

/**
* This is a quick check to see if it is a marker.
* This is needed since there is no other quick way of checking
* for a marker and not adding to the child list.
*
* @return true if this is a marker
*/
protected boolean isMarker() {
return false;
}
}


+ 9
- 0
src/org/apache/fop/fo/FOText.java View File

@@ -51,6 +51,15 @@ public class FOText extends FObj {
structHandler.characters(ca, start, length);
}

/**
* Check if this text node will create an area.
* This means either there is non-whitespace or it is
* preserved whitespace.
* Maybe this just needs to check length > 0, since char iterators
* handle whitespace.
*
* @return true if this will create an area in the output
*/
public boolean willCreateArea() {
if (textInfo.whiteSpaceCollapse == WhiteSpaceCollapse.FALSE &&
length > 0) {

+ 124
- 174
src/org/apache/fop/fo/FObj.java View File

@@ -24,65 +24,73 @@ import java.util.ListIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;

/**
* base class for representation of formatting objects and their processing
*/
public class FObj extends FONode {
protected StructureHandler structHandler;
public PropertyList properties;
protected PropertyManager propMgr;
protected String areaClass = AreaClass.UNASSIGNED;
protected String id = null;
private final static String FO_URI = "http://www.w3.org/1999/XSL/Format";

/**
* value of marker before layout begins
* Static property list builder that converts xml attributes
* into fo properties. This is static since the underlying
* property mappings for fo are also static.
*/
public static final int START = -1000;
protected static PropertyListBuilder plb = null;

/**
* value of marker after break-after
* Structure handler used to notify structure events
* such as start end element.
*/
public static final int BREAK_AFTER = -1001;
protected StructureHandler structHandler;

/**
* where the layout was up to.
* for FObjs it is the child number
* for FOText it is the character number
* Formatting properties for this fo element.
*/
protected int marker = START;

protected ArrayList children = new ArrayList(); // made public for searching for id's

protected boolean isInTableCell = false;
public PropertyList properties;

protected int forcedStartOffset = 0;
protected int forcedWidth = 0;
/**
* Property manager for handler some common properties.
*/
protected PropertyManager propMgr;

protected int widows = 0;
protected int orphans = 0;
/**
* Id of this fo element of null if no id.
*/
protected String id = null;

// count of areas generated-by/returned-by
public int areasGenerated = 0;
/**
* The children of this node.
*/
protected ArrayList children = null;

// markers
protected HashMap markers;
/**
* Markers added to this element.
*/
protected Map markers = null;

/**
* Create a new formatting object.
* All formatting object classes extend this class.
*
* @param parent the parent node
*/
public FObj(FONode parent) {
super(parent);
markers = new HashMap();
if (parent instanceof FObj) {
this.areaClass = ((FObj) parent).areaClass;
}
}

/**
* Set the name of this element.
* The prepends "fo:" to the name to indicate it is in the fo namespace.
*
* @param str the xml element name
*/
public void setName(String str) {
name = "fo:" + str;
}

protected static PropertyListBuilder plb = null;

protected PropertyListBuilder getListBuilder() {
if (plb == null) {
plb = new PropertyListBuilder();
@@ -105,7 +113,6 @@ public class FObj extends FONode {
* will be altered for the next element.
*/
public void handleAttrs(Attributes attlist) throws FOPException {
String uri = "http://www.w3.org/1999/XSL/Format";
FONode par = parent;
while (par != null && !(par instanceof FObj)) {
par = par.parent;
@@ -114,7 +121,7 @@ public class FObj extends FONode {
if (par != null) {
props = ((FObj) par).properties;
}
properties = getListBuilder().makeList(uri, name, attlist, props,
properties = getListBuilder().makeList(FO_URI, name, attlist, props,
(FObj) par);
properties.setFObj(this);
this.propMgr = makePropertyManager(properties);
@@ -126,10 +133,27 @@ public class FObj extends FONode {
return new PropertyManager(propertyList);
}

/**
* Add the child to this object.
*
* @param child the child node to add
*/
protected void addChild(FONode child) {
children.add(child);
if (containsMarkers() && child.isMarker()) {
addMarker((Marker)child);
} else {
if (children == null) {
children = new ArrayList();
}
children.add(child);
}
}

/**
* Set the structure handler for handling structure events.
*
* @param st the structure handler
*/
public void setStructHandler(StructureHandler st) {
structHandler = st;
}
@@ -144,12 +168,18 @@ public class FObj extends FONode {
return (properties.get(name));
}

/**
* Setup the id for this formatting object.
* Most formatting objects can have an id that can be referenced.
* This methods checks that the id isn't already used by another
* fo and sets the id attribute of this object.
*/
protected void setupID() {
Property prop = this.properties.get("id");
if (prop != null) {
String str = prop.getString();
if (str != null && !str.equals("")) {
HashSet idrefs = structHandler.getIDReferences();
Set idrefs = structHandler.getIDReferences();
if (!idrefs.contains(str)) {
id = str;
idrefs.add(id);
@@ -160,33 +190,43 @@ public class FObj extends FONode {
}
}

/**
* Get the id string for this formatting object.
* This will be unique for the fo document.
*
* @return the id string or null if not set
*/
public String getID() {
return id;
}

/**
* Return the "content width" of the areas generated by this FO.
* This is used by percent-based properties to get the dimension of
* the containing block.
* If an FO has a property with a percentage value, that value
* is usually calculated on the basis of the corresponding dimension
* of the area which contains areas generated by the FO.
* NOTE: subclasses of FObj should implement this to return a reasonable
* value!
* Check if this formatting object generates reference areas.
*
* @return true if generates reference areas
*/
public int getContentWidth() {
return 0;
}

public boolean generatesReferenceAreas() {
return false;
}


/**
* Check if this formatting object generates inline areas.
*
* @return true if generates inline areas
*/
public boolean generatesInlineAreas() {
return true;
}

/**
* Check if this formatting object may contain markers.
*
* @return true if this can contian markers
*/
protected boolean containsMarkers() {
return false;
}

/**
* Set writing mode for this FO.
* Find nearest ancestor, including self, which generates
@@ -231,147 +271,57 @@ public class FObj extends FONode {
* this FObj.
*/
public ListIterator getChildren(FONode childNode) {
int i = children.indexOf(childNode);
if (i >= 0) {
return children.listIterator(i);
} else {
return null;
}
}

public void setIsInTableCell() {
this.isInTableCell = true;
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.setIsInTableCell();
}
}
}

public void forceStartOffset(int offset) {
this.forcedStartOffset = offset;
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.forceStartOffset(offset);
}
}
}

public void forceWidth(int width) {
this.forcedWidth = width;
// made recursive by Eric Schaeffer
for (int i = 0; i < this.children.size(); i++) {
Object obj = this.children.get(i);
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.forceWidth(width);
}
}
}

public void resetMarker() {
this.marker = START;
int numChildren = this.children.size();
for (int i = 0; i < numChildren; i++) {
Object obj = this.children.get(i);
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.resetMarker();
if (children != null) {
int i = children.indexOf(childNode);
if (i >= 0) {
return children.listIterator(i);
}
}
}

public void setWidows(int wid) {
widows = wid;
}

public void setOrphans(int orph) {
orphans = orph;
}

public void removeAreas() {
// still to do
}

/**
* At the start of a new span area layout may be partway through a
* nested FO, and balancing requires rollback to this known point.
* The snapshot records exactly where layout is at.
* @param snapshot a ArrayList of markers (Integer)
* @returns the updated ArrayList of markers (Integers)
*/
public ArrayList getMarkerSnapshot(ArrayList snapshot) {
snapshot.add(new Integer(this.marker));

// terminate if no kids or child not yet accessed
if (this.marker < 0) {
return snapshot;
} else if (children.isEmpty()) {
return snapshot;
} else {
return ( (FObj) children.get(this.marker)).getMarkerSnapshot(
snapshot);
}
return null;
}

/**
* When balancing occurs, the flow layout() method restarts at the
* point specified by the current marker snapshot, which is retrieved
* and restored using this method.
* @param snapshot the ArrayList of saved markers (Integers)
* Add the marker to this formatting object.
* If this object can contain markers it checks that the marker
* has a unique class-name for this object and that it is
* the first child.
*/
public void rollback(ArrayList snapshot) {
this.marker = ((Integer) snapshot.get(0)).intValue();
snapshot.remove(0);

if (this.marker == START) {
// make sure all the children of this FO are also reset
resetMarker();
return;
} else if ((this.marker == -1) || children.isEmpty()) {
return;
}

int numChildren = this.children.size();

if (this.marker <= START) {
return;
}

for (int i = this.marker + 1; i < numChildren; i++) {
Object obj = this.children.get(i);
if (obj instanceof FObj) {
FObj child = (FObj) obj;
child.resetMarker();
public void addMarker(Marker marker) {
String mcname = marker.getMarkerClassName();
if (children != null) {
// check for empty children
for (Iterator iter = children.iterator(); iter.hasNext();) {
FONode node = (FONode)iter.next();
if (node instanceof FOText) {
FOText text = (FOText)node;
if (text.willCreateArea()) {
getLogger().error("fo:marker must be an initial child: " + mcname);
return;
} else {
iter.remove();
}
} else {
getLogger().error("fo:marker must be an initial child: " + mcname);
return;
}
}
}
((FObj) children.get(this.marker)).rollback(snapshot);
}


public void addMarker(Marker marker) throws FOPException {
String mcname = marker.getMarkerClassName();
if (!markers.containsKey(mcname) && children.isEmpty()) {
if (markers == null) {
markers = new HashMap();
}
if (!markers.containsKey(mcname)) {
markers.put(mcname, marker);
} else {
getLogger().error("fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
throw new FOPException(
"fo:marker must be an initial child," + "and 'marker-class-name' must be unique for same parent");
getLogger().error("fo:marker 'marker-class-name' must be unique for same parent: " + mcname);
}
}

public boolean hasMarkers() {
return !markers.isEmpty();
return markers != null && !markers.isEmpty();
}

public ArrayList getMarkers() {
return new ArrayList(markers.values());
public Map getMarkers() {
return markers;
}

/**

+ 4
- 3
src/org/apache/fop/fo/FObjMixed.java View File

@@ -22,7 +22,7 @@ import java.util.List;
* and their processing
*/
public class FObjMixed extends FObj {
TextInfo textInfo = null;
protected TextInfo textInfo = null;
protected FontInfo fontInfo = null;

public FObjMixed(FONode parent) {
@@ -35,8 +35,10 @@ public class FObjMixed extends FObj {
}

public void addLayoutManager(List lms) {
lms.add(new InlineStackingLayoutManager(this,
if (children != null) {
lms.add(new InlineStackingLayoutManager(this,
new LMiter(children.listIterator())));
}
}

protected void addCharacters(char data[], int start, int length) {
@@ -54,7 +56,6 @@ public class FObjMixed extends FObj {
}

public void setup() {

if (this.properties != null) {
setupID();
}

+ 1
- 1
src/org/apache/fop/fo/RecursiveCharIterator.java View File

@@ -54,7 +54,7 @@ public class RecursiveCharIterator extends AbstractCharIterator {


private void getNextCharIter() {
if (childIter.hasNext()) {
if (childIter != null && childIter.hasNext()) {
this.curChild = (FONode) childIter.next();
this.curCharIter = curChild.charIterator();
} else {

+ 5
- 0
src/org/apache/fop/fo/flow/BasicLink.java View File

@@ -120,8 +120,13 @@ public class BasicLink extends Inline {

}

protected boolean containsMarkers() {
return true;
}

/**
* Link resolving for resolving internal links.
* This is static since it is independant of the link fo.
*/
protected static class LinkResolver implements Resolveable, Serializable {
private boolean resolved = false;

+ 4
- 0
src/org/apache/fop/fo/flow/BidiOverride.java View File

@@ -74,6 +74,10 @@ public class BidiOverride extends FObjMixed {

}

protected boolean containsMarkers() {
return true;
}

/**
* If this bidi has a different writing mode direction
* ltr or rtl than its parent writing mode then this

+ 2
- 14
src/org/apache/fop/fo/flow/Block.java View File

@@ -52,9 +52,6 @@ public class Block extends FObjMixed {
int blockWidows;
int blockOrphans;

int areaHeight = 0;
int contentWidth = 0;

String id;
int span;
private int wsTreatment; //ENUMERATION
@@ -169,19 +166,10 @@ public class Block extends FObjMixed {

}

public int getAreaHeight() {
return areaHeight;
protected boolean containsMarkers() {
return true;
}


/**
* Return the content width of the boxes generated by this FO.
*/
public int getContentWidth() {
return contentWidth; // getAllocationWidth()??
}


public int getSpan() {
return this.span;
}

+ 4
- 2
src/org/apache/fop/fo/flow/BlockContainer.java View File

@@ -78,8 +78,6 @@ public class BlockContainer extends FObj {
// this.properties.get("width");
// this.properties.get("writing-mode");

this.marker = 0;

this.backgroundColor =
this.properties.get("background-color").getColorType();

@@ -97,6 +95,10 @@ public class BlockContainer extends FObj {
return false;
}

protected boolean containsMarkers() {
return true;
}

public int getSpan() {
return this.span;
}

+ 3
- 0
src/org/apache/fop/fo/flow/Inline.java View File

@@ -87,6 +87,9 @@ public class Inline extends FObjMixed {
}
}

protected boolean containsMarkers() {
return true;
}

public CharIterator charIterator() {
return new InlineCharIterator(this, propMgr.getBorderAndPadding());

+ 4
- 0
src/org/apache/fop/fo/flow/InlineContainer.java View File

@@ -69,6 +69,10 @@ public class InlineContainer extends FObj {
// this.properties.get("writing-mode");
}

protected boolean containsMarkers() {
return true;
}

/**
* This creates a single inline container area after
* laying out the child block areas. All footnotes, floats

+ 4
- 0
src/org/apache/fop/fo/flow/Leader.java View File

@@ -116,6 +116,10 @@ public class Leader extends FObjMixed {

leaderArea = fa;
} else if(leaderPattern == LeaderPattern.USECONTENT) {
if (children == null) {
getLogger().error("Leader use-content with no content");
return;
}
InlineStackingLayoutManager lm;
lm = new InlineStackingLayoutManager(this,
new LMiter(children.listIterator()));

+ 4
- 0
src/org/apache/fop/fo/flow/ListBlock.java View File

@@ -92,5 +92,9 @@ public class ListBlock extends FObj {
return false;
}

protected boolean containsMarkers() {
return true;
}

}


+ 5
- 0
src/org/apache/fop/fo/flow/ListItem.java View File

@@ -99,4 +99,9 @@ public class ListItem extends FObj {
return false;
}

protected boolean containsMarkers() {
return true;
}

}


+ 5
- 0
src/org/apache/fop/fo/flow/ListItemBody.java View File

@@ -46,4 +46,9 @@ public class ListItemBody extends FObj {

}

protected boolean containsMarkers() {
return true;
}

}


+ 5
- 0
src/org/apache/fop/fo/flow/ListItemLabel.java View File

@@ -46,4 +46,9 @@ public class ListItemLabel extends FObj {

}

protected boolean containsMarkers() {
return true;
}

}


+ 26
- 9
src/org/apache/fop/fo/flow/Marker.java View File

@@ -16,31 +16,48 @@ import org.apache.fop.apps.FOPException;

import org.xml.sax.Attributes;

/**
* Marker formatting object.
* This is the marker formatting object that handles merkers.
* This attempts to add itself to the parent formatting object.
*/
public class Marker extends FObjMixed {

private String markerClassName;

/**
* Create a marker fo.
*
* @param parent the parent fo node
*/
public Marker(FONode parent) {
super(parent);
}

/**
* Handle the attributes for this marker.
* This gets the marker-class-name and attempts to add itself
* to the parent formatting object.
*
* @param attlist the attribute list
* @throws FOPException if there is an exception
*/
public void handleAttrs(Attributes attlist) throws FOPException {
super.handleAttrs(attlist);
// do check to see that 'this' is under fo:flow

this.markerClassName =
this.properties.get("marker-class-name").getString();
}

// check to ensure that no other marker with same parent
// has this 'marker-class-name' is in addMarker() method
try {
((FObj)parent).addMarker(this);
} catch (FOPException fopex) {
getLogger().error("marker cannot be added to '" + parent
+ "'");
}
protected boolean isMarker() {
return true;
}

/**
* Get the marker class name for this marker.
*
* @return the marker class name
*/
public String getMarkerClassName() {
return markerClassName;
}

+ 6
- 1
src/org/apache/fop/fo/flow/Table.java View File

@@ -63,7 +63,7 @@ public class Table extends FObj {
tableHeader = (TableBody)child;
} else {
// add bodies
children.add(child);
super.addChild(child);
}
}

@@ -149,4 +149,9 @@ public class Table extends FObj {
return false;
}

protected boolean containsMarkers() {
return true;
}

}


+ 6
- 0
src/org/apache/fop/fo/flow/TableAndCaption.java View File

@@ -51,4 +51,10 @@ public class TableAndCaption extends ToBeImplementedElement {
public boolean generatesInlineAreas() {
return false;
}

protected boolean containsMarkers() {
return true;
}

}


+ 4
- 0
src/org/apache/fop/fo/flow/TableBody.java View File

@@ -70,5 +70,9 @@ public class TableBody extends FObj {

}

protected boolean containsMarkers() {
return true;
}

}


+ 6
- 0
src/org/apache/fop/fo/flow/TableCaption.java View File

@@ -45,4 +45,10 @@ public class TableCaption extends ToBeImplementedElement {
// this.properties.get("width");

}

protected boolean containsMarkers() {
return true;
}

}


+ 4
- 0
src/org/apache/fop/fo/flow/TableCell.java View File

@@ -296,5 +296,9 @@ public class TableCell extends FObj {
}
}
protected boolean containsMarkers() {
return true;
}

}


+ 5
- 0
src/org/apache/fop/fo/flow/Wrapper.java View File

@@ -27,4 +27,9 @@ public class Wrapper extends FObjMixed {
super(parent);
}

protected boolean containsMarkers() {
return true;
}

}


+ 1
- 1
src/org/apache/fop/layoutmgr/LMiter.java View File

@@ -33,7 +33,7 @@ public class LMiter implements ListIterator {

protected boolean preLoadNext() {
// skip over child FObj's that don't add lms
while (baseIter.hasNext()) {
while (baseIter != null && baseIter.hasNext()) {
Object theobj = baseIter.next();
if(theobj instanceof FObj) {
FObj fobj = (FObj) theobj;

Loading…
Cancel
Save