You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2009/09/18 19:10:52 UTC
svn commit: r816718 [5/11] - in
/xmlgraphics/fop/branches/Temp_Accessibility: ./ examples/fo/advanced/
hyph/ lib/ src/codegen/unicode/java/org/apache/fop/hyphenation/
src/codegen/unicode/java/org/apache/fop/text/linebreak/
src/codegen/unicode/java/org/...
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java Fri Sep 18 17:10:42 2009
@@ -22,12 +22,12 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.Constants;
/**
* The set of nodes is sorted into lines indexed into activeLines.
* The nodes in each line are linked together in a single linked list by the
- * KnuthNode.next field. The activeLines array contains a link to the head of
+ * {@link KnuthNode#next} field. The activeLines array contains a link to the head of
* the linked list in index 'line*2' and a link to the tail at index 'line*2+1'.
* <p>
* The set of active nodes can be traversed by
@@ -57,13 +57,42 @@
/** wrap-option = "no-wrap". */
public static final int ONLY_FORCED_BREAKS = 2;
+ /** Holder for symbolic literals for the fitness classes */
+ static final class FitnessClasses {
+ static final int VERY_TIGHT = 0;
+ static final int TIGHT = 1;
+ static final int LOOSE = 2;
+ static final int VERY_LOOSE = 3;
+
+ static final String[] NAMES = { "VERY TIGHT", "TIGHT", "LOOSE", "VERY LOOSE" };
+
+ /**
+ * Figure out the fitness class of this line (tight, loose,
+ * very tight or very loose).
+ * See the section on "More Bells and Whistles" in Knuth's
+ * "Breaking Paragraphs Into Lines".
+ *
+ * @param adjustRatio the adjustment ratio
+ * @return the fitness class
+ */
+ static int computeFitness(double adjustRatio) {
+ if (adjustRatio < -0.5) {
+ return FitnessClasses.VERY_TIGHT;
+ } else if (adjustRatio <= 0.5) {
+ return FitnessClasses.TIGHT;
+ } else if (adjustRatio <= 1.0) {
+ return FitnessClasses.LOOSE;
+ } else {
+ return FitnessClasses.VERY_LOOSE;
+ }
+ }
+ }
+
// parameters of Knuth's algorithm:
- /** Penalty value for flagged penalties. */
- private int flaggedPenalty = 50;
/** Demerit for consecutive lines ending at flagged penalties. */
- protected int repeatedFlaggedDemerit = 50;
+ protected int repeatedFlaggedDemerit = KnuthPenalty.FLAGGED_PENALTY;
/** Demerit for consecutive lines belonging to incompatible fitness classes . */
- protected int incompatibleFitnessDemerit = 50;
+ protected int incompatibleFitnessDemerit = KnuthPenalty.FLAGGED_PENALTY;
/** Maximum number of consecutive lines ending with a flagged penalty.
* Only a value >= 1 is a significant limit.
*/
@@ -110,7 +139,7 @@
/** Alignment of the paragraph's last line. */
protected int alignmentLast;
/** Used to handle the text-indent property (indent the first line of a paragraph). */
- protected boolean bFirst;
+ protected boolean indentFirstPart;
/**
* The set of active nodes in ascending line order. For each line l, activeLines[2l] contains a
@@ -151,30 +180,35 @@
protected BestRecords best;
- /** {@inheritDoc} */
private boolean partOverflowRecoveryActivated = true;
private KnuthNode lastRecovered;
/**
* Create a new instance.
- * @param align alignment of the paragraph/page. One of EN_START, EN_JUSTIFY, etc. For
- * pages EN_BEFORE, EN_AFTER are mapped to the corresponding inline properties
- * (EN_START, EN_END)
+ *
+ * @param align alignment of the paragraph/page. One of {@link Constants#EN_START},
+ * {@link Constants#EN_JUSTIFY}, {@link Constants#EN_CENTER},
+ * {@link Constants#EN_END}.
+ * For pages, {@link Constants#EN_BEFORE} and {@link Constants#EN_AFTER}
+ * are mapped to the corresponding inline properties,
+ * {@link Constants#EN_START} and {@link Constants#EN_END}.
* @param alignLast alignment of the paragraph's last line
- * @param first for the text-indent property (indent the first line of a paragraph)
- * @param partOverflowRecovery true if too long elements should be moved to the next line/part
- * @param maxFlagCount maximum allowed number of consecutive lines ending at a flagged penalty
- * item
+ * @param first for the text-indent property ({@code true} if the first line
+ * of a paragraph should be indented)
+ * @param partOverflowRecovery {@code true} if too long elements should be moved to
+ * the next line/part
+ * @param maxFlagCount maximum allowed number of consecutive lines ending at a flagged penalty
+ * item
*/
public BreakingAlgorithm(int align, int alignLast,
boolean first, boolean partOverflowRecovery,
int maxFlagCount) {
- alignment = align;
- alignmentLast = alignLast;
- bFirst = first;
+ this.alignment = align;
+ this.alignmentLast = alignLast;
+ this.indentFirstPart = first;
this.partOverflowRecoveryActivated = partOverflowRecovery;
this.best = new BestRecords();
- maxFlaggedPenaltiesCount = maxFlagCount;
+ this.maxFlaggedPenaltiesCount = maxFlagCount;
}
@@ -183,34 +217,34 @@
*/
public class KnuthNode {
/** index of the breakpoint represented by this node */
- public int position;
+ public final int position;
/** number of the line ending at this breakpoint */
- public int line;
+ public final int line;
/** fitness class of the line ending at this breakpoint. One of 0, 1, 2, 3. */
- public int fitness;
+ public final int fitness;
/** accumulated width of the KnuthElements up to after this breakpoint. */
- public int totalWidth;
+ public final int totalWidth;
/** accumulated stretchability of the KnuthElements up to after this breakpoint. */
- public int totalStretch;
+ public final int totalStretch;
/** accumulated shrinkability of the KnuthElements up to after this breakpoint. */
- public int totalShrink;
+ public final int totalShrink;
/** adjustment ratio if the line ends at this breakpoint */
- public double adjustRatio;
+ public final double adjustRatio;
/** available stretch of the line ending at this breakpoint */
- public int availableShrink;
+ public final int availableShrink;
/** available shrink of the line ending at this breakpoint */
- public int availableStretch;
+ public final int availableStretch;
/** difference between target and actual line width */
- public int difference;
+ public final int difference;
/** minimum total demerits up to this breakpoint */
public double totalDemerits;
@@ -249,7 +283,8 @@
return "<KnuthNode at " + position + " "
+ totalWidth + "+" + totalStretch + "-" + totalShrink
+ " line:" + line + " prev:" + (previous != null ? previous.position : -1)
- + " dem:" + totalDemerits + ">";
+ + " dem:" + totalDemerits
+ + " fitness:" + FitnessClasses.NAMES[fitness] + ">";
}
}
@@ -258,7 +293,6 @@
*/
protected class BestRecords {
private static final double INFINITE_DEMERITS = Double.POSITIVE_INFINITY;
- //private static final double INFINITE_DEMERITS = 1E11;
private double[] bestDemerits = new double[4];
private KnuthNode[] bestNode = new KnuthNode[4];
@@ -333,7 +367,7 @@
return bestAvailableStretch[fitness];
}
- public int getDifference(int fitness) {
+ public int getDifference(int fitness) {
return bestDifference[fitness];
}
@@ -373,20 +407,21 @@
return this.partOverflowRecoveryActivated;
}
- /** Empty method, hook for subclasses. Called before determining the optimal
+ /**
+ * Empty method, hook for subclasses. Called before determining the optimal
* breakpoints corresponding to a given active node.
* @param total number of lines for the active node
* @param demerits total demerits of the paragraph for the active node
*/
public abstract void updateData1(int total, double demerits);
- /** Empty method, hook for subclasses. Called when determining the optimal breakpoints
+ /**
+ * Empty method, hook for subclasses. Called when determining the optimal breakpoints
* for a given active node.
* @param bestActiveNode a node in the chain of best active nodes, corresponding to
* one of the optimal breakpoints
* @param sequence the corresponding paragraph
* @param total the number of lines into which the paragraph will be broken
- * @see #calculateBreakPoints(KnuthNode, KnuthSequence, int)
*/
public abstract void updateData2(KnuthNode bestActiveNode,
KnuthSequence sequence,
@@ -404,13 +439,18 @@
return findBreakingPoints(par, 0, threshold, force, allowedBreaks);
}
- /** Finds an optimal set of breakpoints for the given paragraph.
- * @param par the paragraph to break
- * @param startIndex index of the Knuth element at which the breaking must start
- * @param threshold upper bound of the adjustment ratio
- * @param force true if a set of breakpoints must be found even if there are no
- * feasible ones
- * @param allowedBreaks one of ONLY_FORCED_BREAKS, NO_FLAGGED_PENALTIES, ALL_BREAKS
+ /**
+ * Finds an optimal set of breakpoints for the given paragraph.
+ *
+ * @param par the paragraph to break
+ * @param startIndex index of the Knuth element at which the breaking must start
+ * @param threshold upper bound of the adjustment ratio
+ * @param force {@code true} if a set of breakpoints must be found, even
+ * if there are no feasible ones
+ * @param allowedBreaks the type(s) of breaks allowed. One of {@link #ONLY_FORCED_BREAKS},
+ * {@link #NO_FLAGGED_PENALTIES} or {@link #ALL_BREAKS}.
+ *
+ * @return the number of effective breaks
*/
public int findBreakingPoints(KnuthSequence par, int startIndex,
double threshold, boolean force,
@@ -418,142 +458,69 @@
this.par = par;
this.threshold = threshold;
this.force = force;
- //this.lineWidth = lineWidth;
- initialize();
- activeLines = new KnuthNode[20];
+ // initialize the algorithm
+ initialize();
- // reset lastTooShort and lastTooLong, as they could be not null
- // because of previous calls to findBreakingPoints
- lastTooShort = lastTooLong = null;
- // reset startLine and endLine
- startLine = endLine = 0;
- // current element in the paragraph
- KnuthElement thisElement = null;
// previous element in the paragraph is a KnuthBox?
boolean previousIsBox = false;
- // index of the first KnuthBox in the sequence
+ // index of the first KnuthBox in the sequence, in case of non-centered
+ // alignment. For centered alignment, we need to take into account preceding
+ // penalties+glues used for the filler spaces
int firstBoxIndex = startIndex;
- if (alignment != org.apache.fop.fo.Constants.EN_CENTER) {
- while (par.size() > firstBoxIndex
- && !((KnuthElement) par.get(firstBoxIndex)).isBox()) {
- firstBoxIndex++;
- }
+ if (alignment != Constants.EN_CENTER) {
+ firstBoxIndex = par.getFirstBoxIndex(startIndex);
}
+ firstBoxIndex = (firstBoxIndex < 0) ? 0 : firstBoxIndex;
// create an active node representing the starting point
- activeLines = new KnuthNode[20];
addNode(0, createNode(firstBoxIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
+ KnuthNode lastForced = getNode(0);
+
if (log.isTraceEnabled()) {
log.trace("Looping over " + (par.size() - startIndex) + " elements");
+ log.trace(par);
}
- KnuthNode lastForced = getNode(0);
-
// main loop
- for (int i = startIndex; i < par.size(); i++) {
- thisElement = getElement(i);
- if (thisElement.isBox()) {
- // a KnuthBox object is not a legal line break
- totalWidth += thisElement.getW();
- previousIsBox = true;
- handleBox((KnuthBox) thisElement);
- } else if (thisElement.isGlue()) {
- // a KnuthGlue object is a legal line break
- // only if the previous object is a KnuthBox
- // consider these glues according to the value of allowedBreaks
- if (previousIsBox
- && !(allowedBreaks == ONLY_FORCED_BREAKS)) {
- considerLegalBreak(thisElement, i);
- }
- totalWidth += thisElement.getW();
- totalStretch += thisElement.getY();
- totalShrink += thisElement.getZ();
- previousIsBox = false;
- } else {
- // a KnuthPenalty is a legal line break
- // only if its penalty is not infinite;
- // consider all penalties, non-flagged penalties or non-forcing penalties
- // according to the value of allowedBreaks
- if (((KnuthPenalty) thisElement).getP() < KnuthElement.INFINITE
- && (!(allowedBreaks == NO_FLAGGED_PENALTIES)
- || !(((KnuthPenalty) thisElement).isFlagged()))
- && (!(allowedBreaks == ONLY_FORCED_BREAKS)
- || ((KnuthPenalty) thisElement).getP() == -KnuthElement.INFINITE)) {
- considerLegalBreak(thisElement, i);
- }
- previousIsBox = false;
- }
+ for (int elementIndex = startIndex; elementIndex < par.size(); elementIndex++) {
+
+ previousIsBox = handleElementAt(
+ elementIndex, previousIsBox, allowedBreaks).isBox();
+
if (activeNodeCount == 0) {
+ if (ipdChanged()) {
+ return handleIpdChange();
+ }
if (!force) {
log.debug("Could not find a set of breaking points " + threshold);
return 0;
}
+
// lastDeactivated was a "good" break, while lastTooShort and lastTooLong
// were "bad" breaks since the beginning;
// if it is not the node we just restarted from, lastDeactivated can
// replace either lastTooShort or lastTooLong
- if (lastDeactivated != null && lastDeactivated != lastForced) {
- if (lastDeactivated.adjustRatio > 0) {
- lastTooShort = lastDeactivated;
- } else {
- lastTooLong = lastDeactivated;
- }
+ if (lastDeactivated != null
+ && lastDeactivated != lastForced) {
+ replaceLastDeactivated();
}
- if (lastTooShort == null || lastForced.position == lastTooShort.position) {
- if (isPartOverflowRecoveryActivated()) {
- if (this.lastRecovered == null) {
- this.lastRecovered = lastTooLong;
- if (log.isDebugEnabled()) {
- log.debug("Recovery point: " + lastRecovered);
- }
- }
- // content would overflow, insert empty line/page and try again
- KnuthNode node = createNode(
- lastTooLong.previous.position, lastTooLong.previous.line + 1, 1,
- 0, 0, 0,
- 0, 0, 0,
- 0, 0, lastTooLong.previous);
- lastForced = node;
- node.fitRecoveryCounter = lastTooLong.previous.fitRecoveryCounter + 1;
- if (log.isDebugEnabled()) {
- log.debug("first part doesn't fit into line, recovering: "
- + node.fitRecoveryCounter);
- }
- if (node.fitRecoveryCounter > getMaxRecoveryAttempts()) {
- while (lastForced.fitRecoveryCounter > 0) {
- lastForced = lastForced.previous;
- lastDeactivated = lastForced.previous;
- startLine--;
- endLine--;
- }
- lastForced = this.lastRecovered;
- this.lastRecovered = null;
- startLine = lastForced.line;
- endLine = lastForced.line;
- log.debug("rolled back...");
- }
- } else {
- lastForced = lastTooLong;
- }
+
+ if (lastTooShort == null
+ || lastForced.position == lastTooShort.position) {
+ lastForced = recoverFromOverflow();
} else {
lastForced = lastTooShort;
this.lastRecovered = null;
}
-
- if (log.isDebugEnabled()) {
- log.debug("Restarting at node " + lastForced);
- }
- i = restartFrom(lastForced, i);
+ elementIndex = restartFrom(lastForced, elementIndex);
}
+
}
+
finish();
- if (log.isTraceEnabled()) {
- log.trace("Main loop completed " + activeNodeCount);
- log.trace("Active nodes=" + toString(""));
- }
// there is at least one set of breaking points
// select one or more active nodes, removing the others from the list
@@ -571,42 +538,49 @@
return line;
}
+ protected boolean ipdChanged() {
+ return false;
+ }
+
+ protected int handleIpdChange() {
+ throw new IllegalStateException();
+ }
+
/**
- * This method tries to find the context FO for a position in a KnuthSequence.
- * @param seq the KnuthSequence to inspect
- * @param position the index of the position in the KnuthSequence
- * @return the requested context FO note or null, if no context node could be determined
- */
- private FONode findContextFO(KnuthSequence seq, int position) {
- ListElement el = seq.getElement(position);
- while (el.getLayoutManager() == null && position < seq.size() - 1) {
- position++;
- el = seq.getElement(position);
- }
- Position pos = (el != null ? el.getPosition() : null);
- LayoutManager lm = (pos != null ? pos.getLM() : null);
- while (pos instanceof NonLeafPosition) {
- pos = ((NonLeafPosition)pos).getPosition();
- if (pos != null && pos.getLM() != null) {
- lm = pos.getLM();
- }
- }
- if (lm != null) {
- return lm.getFObj();
- } else {
- return null;
+ * Recover from a {@link KnuthNode} leading to a line that is too long.
+ * The default implementation creates a new node corresponding to a break
+ * point after the previous node that led to a line that was too short.
+ *
+ * @param lastTooLong the node that leads to a "too long" line
+ * @return node corresponding to a breakpoint after the previous "too short" line
+ */
+ protected KnuthNode recoverFromTooLong(KnuthNode lastTooLong) {
+ if (log.isDebugEnabled()) {
+ log.debug("Recovering from too long: " + lastTooLong);
}
+
+ // content would overflow, insert empty line/page and try again
+ return createNode(
+ lastTooLong.previous.position, lastTooLong.previous.line + 1, 1,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, lastTooLong.previous);
}
- /** Resets the algorithm's variables. */
+ /** Initializes the algorithm's variables. */
protected void initialize() {
this.totalWidth = 0;
this.totalStretch = 0;
this.totalShrink = 0;
+ this.lastTooShort = this.lastTooLong = null;
+ this.startLine = this.endLine = 0;
+ this.activeLines = new KnuthNode[20];
}
- /** Creates a new active node for a feasible breakpoint at the given position. Only
+ /**
+ * Creates a new active node for a feasible breakpoint at the given position. Only
* called in forced mode.
+ *
* @param position index of the element in the Knuth sequence
* @param line number of the line ending at the breakpoint
* @param fitness fitness class of the line ending at the breakpoint. One of 0, 1, 2, 3.
@@ -621,6 +595,7 @@
* @param difference difference between target and actual line width
* @param totalDemerits minimum total demerits up to the breakpoint
* @param previous active node for the preceding breakpoint
+ * @return a new node
*/
protected KnuthNode createNode(int position, int line, int fitness,
int totalWidth, int totalStretch, int totalShrink,
@@ -646,11 +621,173 @@
best.getNode(fitness));
}
- /** Empty method, hook for subclasses. */
+ /**
+ * Return the last node that yielded a too short line.
+ * @return the node corresponding to the last too short line
+ */
+ protected final KnuthNode getLastTooShort() {
+ return this.lastTooShort;
+ }
+
+ /**
+ * Generic handler for a {@link KnuthElement} at the given {@code position},
+ * taking into account whether the preceding element was a box, and which
+ * type(s) of breaks are allowed.
+ * Non-overridable. This method simply serves to route the call to one of the
+ * more specific handlers ({@link #handleBox(KnuthBox)},
+ * {@link #handleGlueAt(KnuthGlue,int,boolean,int)} or
+ * {@link #handlePenaltyAt(KnuthPenalty,int,int)}. The specialized handlers
+ * can be overridden by subclasses to add to or modify the default behavior
+ * for the different types of elements.
+ *
+ * @param position the position index of the element in the paragraph
+ * @param previousIsBox {@code true} if the previous element is a box
+ * @param allowedBreaks the type(s) of breaks allowed; should be one
+ * of {@link #ALL_BREAKS}, {@link #NO_FLAGGED_PENALTIES}
+ * or {@link #ONLY_FORCED_BREAKS}
+ * @return the handled element
+ */
+ protected final KnuthElement handleElementAt(int position,
+ boolean previousIsBox,
+ int allowedBreaks) {
+ KnuthElement element = getElement(position);
+ if (element.isBox()) {
+ handleBox((KnuthBox) element);
+ } else if (element.isGlue()) {
+ handleGlueAt((KnuthGlue) element, position, previousIsBox, allowedBreaks);
+ } else if (element.isPenalty()){
+ handlePenaltyAt((KnuthPenalty) element, position, allowedBreaks);
+ } else {
+ throw new IllegalArgumentException(
+ "Unknown KnuthElement type: expecting KnuthBox, KnuthGlue or KnuthPenalty");
+ }
+ return element;
+ }
+
+ /**
+ * Handle a {@link KnuthBox}.
+ * <br/><em>Note: default implementation just adds the box's width
+ * to the total content width. Subclasses that do not keep track
+ * of this themselves, but override this method, should remember
+ * to call {@code super.handleBox(box)} to avoid unwanted side-effects.</em>
+ *
+ * @param box the {@link KnuthBox} to handle
+ */
protected void handleBox(KnuthBox box) {
+ // a KnuthBox object is not a legal line break,
+ // just add the width to the total
+ totalWidth += box.getW();
}
+ /**
+ * Handle a {@link KnuthGlue} at the given position,
+ * taking into account the additional parameters.
+ *
+ * @param glue the {@link KnuthGlue} to handle
+ * @param position the position of the glue in the list
+ * @param previousIsBox {@code true} if the preceding element is a box
+ * @param allowedBreaks the type of breaks that are allowed
+ */
+ protected void handleGlueAt(KnuthGlue glue, int position,
+ boolean previousIsBox, int allowedBreaks) {
+ // a KnuthGlue object is a legal line break
+ // only if the previous object is a KnuthBox
+ // consider these glues according to the value of allowedBreaks
+ if (previousIsBox
+ && !(allowedBreaks == ONLY_FORCED_BREAKS)) {
+ considerLegalBreak(glue, position);
+ }
+ totalWidth += glue.getW();
+ totalStretch += glue.getY();
+ totalShrink += glue.getZ();
+ }
+
+ /**
+ * Handle a {@link KnuthPenalty} at the given position,
+ * taking into account the type of breaks allowed.
+ *
+ * @param penalty the {@link KnuthPenalty} to handle
+ * @param position the position of the penalty in the list
+ * @param allowedBreaks the type of breaks that are allowed
+ */
+ protected void handlePenaltyAt(KnuthPenalty penalty, int position,
+ int allowedBreaks) {
+ // a KnuthPenalty is a legal line break
+ // only if its penalty is not infinite;
+ // consider all penalties, non-flagged penalties or non-forcing penalties
+ // according to the value of allowedBreaks
+ if (((penalty.getP() < KnuthElement.INFINITE)
+ && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isFlagged())
+ && (!(allowedBreaks == ONLY_FORCED_BREAKS)
+ || penalty.isForcedBreak()))) {
+ considerLegalBreak(penalty, position);
+ }
+ }
+
+ /**
+ * Replace the last too-long or too-short node by the last deactivated
+ * node, if applicable.
+ */
+ protected final void replaceLastDeactivated() {
+ if (lastDeactivated.adjustRatio > 0) {
+ //last deactivated was too short
+ lastTooShort = lastDeactivated;
+ } else {
+ //last deactivated was too long or exactly the right width
+ lastTooLong = lastDeactivated;
+ }
+ }
+
+ /**
+ * Recover from an overflow condition.
+ *
+ * @return the new {@code lastForced} node
+ */
+ protected KnuthNode recoverFromOverflow() {
+ KnuthNode lastForced;
+ if (isPartOverflowRecoveryActivated()) {
+ if (lastRecovered == null) {
+ lastRecovered = lastTooLong;
+ if (log.isDebugEnabled()) {
+ log.debug("Recovery point: " + lastRecovered);
+ }
+ }
+ KnuthNode node = recoverFromTooLong(lastTooLong);
+ lastForced = node;
+ node.fitRecoveryCounter = lastTooLong.previous.fitRecoveryCounter + 1;
+ if (log.isDebugEnabled()) {
+ log.debug("first part doesn't fit into line, recovering: "
+ + node.fitRecoveryCounter);
+ }
+ if (node.fitRecoveryCounter > getMaxRecoveryAttempts()) {
+ while (lastForced.fitRecoveryCounter > 0
+ && lastForced.previous != null) {
+ lastForced = lastForced.previous;
+ lastDeactivated = lastForced.previous;
+ }
+ lastForced = lastRecovered;
+ lastRecovered = null;
+ startLine = lastForced.line;
+ endLine = lastForced.line;
+ log.debug("rolled back...");
+ }
+ } else {
+ lastForced = lastTooLong;
+ }
+ return lastForced;
+ }
+
+ /**
+ * Restart from the given node at the given index.
+ *
+ * @param restartingNode the {@link KnuthNode} to restart from
+ * @param currentIndex the current position index
+ * @return the index of the restart point
+ */
protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
+ if (log.isDebugEnabled()) {
+ log.debug("Restarting at node " + restartingNode);
+ }
restartingNode.totalDemerits = 0;
addNode(restartingNode.line, restartingNode);
startLine = restartingNode.line;
@@ -672,7 +809,8 @@
return restartingIndex;
}
- /** Determines if the given breakpoint is a feasible breakpoint. That is, if a decent
+ /**
+ * Determines if the given breakpoint is a feasible breakpoint. That is, if a decent
* line may be built between one of the currently active nodes and this breakpoint.
* @param element the paragraph's element to consider
* @param elementIdx the element's index inside the paragraph
@@ -694,9 +832,15 @@
continue;
}
int difference = computeDifference(node, element, elementIdx);
+ if (!elementCanEndLine(element, endLine, difference)) {
+ log.trace("Skipping legal break");
+ break;
+ }
+
double r = computeAdjustmentRatio(node, difference);
int availableShrink = totalShrink - node.totalShrink;
int availableStretch = totalStretch - node.totalStretch;
+
if (log.isTraceEnabled()) {
log.trace("\tr=" + r + " difference=" + difference);
log.trace("\tline=" + line);
@@ -704,87 +848,22 @@
// The line would be too long.
if (r < -1 || element.isForcedBreak()) {
- // Deactivate node.
- if (log.isTraceEnabled()) {
- log.trace("Removing " + node);
- }
- removeNode(line, node);
- lastDeactivated = compareNodes(lastDeactivated, node);
+ deactivateNode(node, line);
}
+ int fitnessClass = FitnessClasses.computeFitness(r);
+ double demerits = computeDemerits(node, element, fitnessClass, r);
// The line is within the available shrink and the threshold.
if (r >= -1 && r <= threshold) {
- int fitnessClass = computeFitness(r);
- double demerits = computeDemerits(node, element, fitnessClass, r);
-
- if (log.isTraceEnabled()) {
- log.trace("\tDemerits=" + demerits);
- log.trace("\tFitness class=" + fitnessClass);
- }
-
- if (demerits < best.getDemerits(fitnessClass)) {
- // updates best demerits data
- best.addRecord(demerits, node, r, availableShrink, availableStretch,
- difference, fitnessClass);
- lastTooShort = null;
- }
+ activateNode(node, difference, r,
+ demerits, fitnessClass, availableShrink, availableStretch);
}
- // The line is way too short, but we are in forcing mode, so a node is
+ // The line is way too short/long, but we are in forcing mode, so a node is
// calculated and stored in lastValidNode.
if (force && (r <= -1 || r > threshold)) {
- int fitnessClass = computeFitness(r);
- double demerits = computeDemerits(node, element, fitnessClass, r);
- int newWidth = totalWidth;
- int newStretch = totalStretch;
- int newShrink = totalShrink;
-
- // add the width, stretch and shrink of glue elements after
- // the break
- // this does not affect the dimension of the line / page, only
- // the values stored in the node; these would be as if the break
- // was just before the next box element, thus ignoring glues and
- // penalties between the "real" break and the following box
- for (int i = elementIdx; i < par.size(); i++) {
- KnuthElement tempElement = getElement(i);
- if (tempElement.isBox()) {
- break;
- } else if (tempElement.isGlue()) {
- newWidth += tempElement.getW();
- newStretch += tempElement.getY();
- newShrink += tempElement.getZ();
- } else if (tempElement.isForcedBreak() && i != elementIdx) {
- break;
- }
- }
-
- if (r <= -1) {
- if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
- lastTooLong = createNode(elementIdx, line + 1, fitnessClass,
- newWidth, newStretch, newShrink,
- r, availableShrink, availableStretch,
- difference, demerits, node);
- if (log.isTraceEnabled()) {
- log.trace("Picking tooLong " + lastTooLong);
- }
- }
- } else {
- if (lastTooShort == null || demerits <= lastTooShort.totalDemerits) {
- if (considerTooShort) {
- //consider possibilities which are too short
- best.addRecord(demerits, node, r,
- availableShrink, availableStretch,
- difference, fitnessClass);
- }
- lastTooShort = createNode(elementIdx, line + 1, fitnessClass,
- newWidth, newStretch, newShrink,
- r, availableShrink, availableStretch,
- difference, demerits, node);
- if (log.isTraceEnabled()) {
- log.trace("Picking tooShort " + lastTooShort);
- }
- }
- }
+ forceNode(node, line, elementIdx, difference, r,
+ demerits, fitnessClass, availableShrink, availableStretch);
}
}
addBreaks(line, elementIdx);
@@ -792,6 +871,145 @@
}
/**
+ * Check if the given {@link KnuthElement} can end the line with the given
+ * number.
+ * @param element the element
+ * @param line the line number
+ * @param difference
+ * @return {@code true} if the element can end the line
+ */
+ protected boolean elementCanEndLine(KnuthElement element, int line, int difference) {
+ return (!element.isPenalty()
+ || element.getP() < KnuthElement.INFINITE);
+ }
+
+ /**
+ * Force the given {@link KnuthNode}, and register it.
+ *
+ * @param node the node
+ * @param line the line number
+ * @param elementIdx the position index of the element
+ * @param difference the difference between content-length and avaialable width
+ * @param r the adjustment ratio
+ * @param demerits demerits produced by the node
+ * @param fitnessClass the fitness class
+ * @param availableShrink the available amount of shrink
+ * @param availableStretch tha available amount of stretch
+ */
+ protected void forceNode(KnuthNode node,
+ int line,
+ int elementIdx,
+ int difference,
+ double r,
+ double demerits,
+ int fitnessClass,
+ int availableShrink,
+ int availableStretch) {
+
+ int newWidth = totalWidth;
+ int newStretch = totalStretch;
+ int newShrink = totalShrink;
+
+ // add the width, stretch and shrink of glue elements after
+ // the break
+ // this does not affect the dimension of the line / page, only
+ // the values stored in the node; these would be as if the break
+ // was just before the next box element, thus ignoring glues and
+ // penalties between the "real" break and the following box
+ for (int i = elementIdx; i < par.size(); i++) {
+ KnuthElement tempElement = getElement(i);
+ if (tempElement.isBox()) {
+ break;
+ } else if (tempElement.isGlue()) {
+ newWidth += tempElement.getW();
+ newStretch += tempElement.getY();
+ newShrink += tempElement.getZ();
+ } else if (tempElement.isForcedBreak() && i != elementIdx) {
+ break;
+ }
+ }
+
+ if (r <= -1) {
+ log.debug("Considering tooLong, demerits=" + demerits);
+ if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
+ lastTooLong = createNode(elementIdx, line + 1, fitnessClass,
+ newWidth, newStretch, newShrink,
+ r, availableShrink, availableStretch,
+ difference, demerits, node);
+ if (log.isTraceEnabled()) {
+ log.trace("Picking tooLong " + lastTooLong);
+ }
+ }
+ } else {
+ if (lastTooShort == null || demerits <= lastTooShort.totalDemerits) {
+ if (considerTooShort) {
+ //consider possibilities which are too short
+ best.addRecord(demerits, node, r,
+ availableShrink, availableStretch,
+ difference, fitnessClass);
+ }
+ lastTooShort = createNode(elementIdx, line + 1, fitnessClass,
+ newWidth, newStretch, newShrink,
+ r, availableShrink, availableStretch,
+ difference, demerits, node);
+ if (log.isTraceEnabled()) {
+ log.trace("Picking tooShort " + lastTooShort);
+ }
+ }
+ }
+ }
+
+ /**
+ * Activate the given node. Will result in the given {@link KnuthNode}
+ * being registered as a feasible breakpoint, if the {@code demerits} are better
+ * than that of the best node registered for the given {@code fitnessClass}.
+ *
+ * @param node the node
+ * @param difference the difference between content-length and available width
+ * @param r the adjustment ratio
+ * @param demerits demerits produced by the node
+ * @param fitnessClass the fitness class
+ * @param availableShrink the available amount of shrink
+ * @param availableStretch the available amount of stretch
+ */
+ protected void activateNode(KnuthNode node,
+ int difference,
+ double r,
+ double demerits,
+ int fitnessClass,
+ int availableShrink,
+ int availableStretch) {
+
+ if (log.isTraceEnabled()) {
+ log.trace("\tDemerits=" + demerits);
+ log.trace("\tFitness class=" + FitnessClasses.NAMES[fitnessClass]);
+ }
+
+ if (demerits < best.getDemerits(fitnessClass)) {
+ // updates best demerits data
+ best.addRecord(demerits, node, r, availableShrink, availableStretch,
+ difference, fitnessClass);
+ lastTooShort = null;
+ }
+ }
+
+ /**
+ * Deactivate the given node
+ *
+ * @param node the node
+ * @param line the line number
+ */
+ protected void deactivateNode(KnuthNode node, int line) {
+ // Deactivate node...
+ if (log.isTraceEnabled()) {
+ log.trace("Removing " + node);
+ }
+ removeNode(line, node);
+ // ... and remember it, if it was a good candidate
+ lastDeactivated = compareNodes(lastDeactivated, node);
+ }
+
+ /**
* Adds new active nodes for breaks at the given element.
* @param line number of the previous line; this element will end line number (line+1)
* @param elementIdx the element's index
@@ -832,7 +1050,7 @@
// by line number and position;
if (log.isTraceEnabled()) {
log.trace("\tInsert new break in list of " + activeNodeCount
- + " from fitness class " + i);
+ + " from fitness class " + FitnessClasses.NAMES[i]);
}
KnuthNode newNode = createNode(elementIdx, line + 1, i,
newWidth, newStretch, newShrink);
@@ -846,8 +1064,9 @@
* Return the difference between the natural width of a line that would be made
* between the given active node and the given element, and the available width of the
* real line.
- * @param activeNode node for the previous breakpoint
- * @param element currently considered breakpoint
+ * @param activeNode node for the previous breakpoint
+ * @param element currently considered breakpoint
+ * @param elementIndex index of the element that is considered as a breakpoint
* @return The difference in width. Positive numbers mean extra space in the line,
* negative number that the line overflows.
*/
@@ -862,7 +1081,7 @@
}
/**
- * Return the adjust ration needed to make up for the difference. A ration of
+ * Return the adjustment ratio needed to make up for the difference. A ratio of
* <ul>
* <li>0 means that the break has the exact right width</li>
* <li>>= -1 && < 0 means that the break is wider than the line,
@@ -871,9 +1090,9 @@
* but within the maximum values of the glues.</li>
* <li>> 1 means that the break is too small to make up for the glues.</li>
* </ul>
- * @param activeNode
- * @param difference
- * @return The ration.
+ * @param activeNode the currently active node
+ * @param difference the difference between content-length and available width
+ * @return The adjustment ratio.
*/
protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
// compute the adjustment ratio
@@ -897,26 +1116,6 @@
}
/**
- * Figure out the fitness class of this line (tight, loose,
- * very tight or very loose).
- * See the section on "More Bells and Whistles" in Knuth's
- * "Breaking Paragraphs Into Lines".
- * @param r
- * @return the fitness class
- */
- private int computeFitness(double r) {
- if (r < -0.5) {
- return 0;
- } else if (r <= 0.5) {
- return 1;
- } else if (r <= 1) {
- return 2;
- } else {
- return 3;
- }
- }
-
- /**
* Computes the demerits of the current breaking (that is, up to the given element),
* if the next-to-last chosen breakpoint is the given active node. This adds to the
* total demerits of the given active node, the demerits of a line starting at this
@@ -933,12 +1132,16 @@
// compute demerits
double f = Math.abs(r);
f = 1 + 100 * f * f * f;
- if (element.isPenalty() && element.getP() >= 0) {
- f += element.getP();
- demerits = f * f;
- } else if (element.isPenalty() && !element.isForcedBreak()) {
+ if (element.isPenalty()) {
double penalty = element.getP();
- demerits = f * f - penalty * penalty;
+ if (penalty >= 0) {
+ f += penalty;
+ demerits = f * f;
+ } else if (!element.isForcedBreak()) {
+ demerits = f * f - penalty * penalty;
+ } else {
+ demerits = f * f;
+ }
} else {
demerits = f * f;
}
@@ -982,7 +1185,15 @@
return demerits;
}
+ /**
+ * Hook for subclasses to trigger special behavior after ending the
+ * main loop in {@link #findBreakingPoints(KnuthSequence,int,double,boolean,int)}
+ */
protected void finish() {
+ if (log.isTraceEnabled()) {
+ log.trace("Main loop completed " + activeNodeCount);
+ log.trace("Active nodes=" + toString(""));
+ }
}
/**
@@ -1083,12 +1294,8 @@
* @return the width/length in millipoints
*/
protected int getLineWidth(int line) {
- if (this.lineWidth < 0) {
- throw new IllegalStateException("lineWidth must be set"
- + (this.lineWidth != 0 ? " and positive, but it is: " + this.lineWidth : ""));
- } else {
- return this.lineWidth;
- }
+ assert lineWidth >= 0;
+ return this.lineWidth;
}
/** @return the constant line/part width or -1 if there is no such value */
@@ -1106,10 +1313,10 @@
sb.append("[\n");
for (int i = startLine; i < endLine; i++) {
for (KnuthNode node = getNode(i); node != null; node = node.next) {
- sb.append(prepend + "\t" + node + ",\n");
+ sb.append(prepend).append('\t').append(node).append(",\n");
}
}
- sb.append(prepend + "]");
+ sb.append(prepend).append("]");
return sb.toString();
}
@@ -1121,7 +1328,7 @@
* @param par the corresponding paragraph
* @param total the number of lines into which the paragraph will be broken
*/
- private void calculateBreakPoints(KnuthNode node, KnuthSequence par,
+ protected void calculateBreakPoints(KnuthNode node, KnuthSequence par,
int total) {
KnuthNode bestActiveNode = node;
// use bestActiveNode to determine the optimum breakpoints
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java Fri Sep 18 17:10:42 2009
@@ -22,14 +22,14 @@
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.pagination.Flow;
-import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
-import org.apache.fop.layoutmgr.inline.WrapperLayoutManager;
/**
* LayoutManager for an fo:flow object.
@@ -63,108 +63,151 @@
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
- // set layout dimensions
- int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
- int flowBPD = getCurrentPV().getBodyRegion().getBPD();
-
- // currently active LM
- LayoutManager curLM;
- List returnedList;
- List returnList = new LinkedList();
+ List elements = new LinkedList();
- while ((curLM = getChildLM()) != null) {
- if (!(curLM instanceof WrapperLayoutManager)
- && curLM instanceof InlineLevelLayoutManager) {
- log.error("inline area not allowed under flow - ignoring");
- curLM.setFinished(true);
- continue;
+ LayoutManager currentChildLM;
+ while ((currentChildLM = getChildLM()) != null) {
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
}
+ }
- int span = EN_NONE;
- int disableColumnBalancing = EN_FALSE;
- if (curLM instanceof BlockLayoutManager) {
- span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
- disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO()
- .getDisableColumnBalancing();
- } else if (curLM instanceof BlockContainerLayoutManager) {
- span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
- disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO()
- .getDisableColumnBalancing();
- }
+ SpaceResolver.resolveElementList(elements);
+ setFinished(true);
- int currentSpan = context.getCurrentSpan();
- if (currentSpan != span) {
- if (span == EN_ALL) {
- context.setDisableColumnBalancing(disableColumnBalancing);
- }
- log.debug("span change from " + currentSpan + " to " + span);
- context.signalSpanChange(span);
- SpaceResolver.resolveElementList(returnList);
- return returnList;
- }
+ assert !elements.isEmpty();
+ return elements;
+ }
- // Set up a LayoutContext
- //MinOptMax bpd = context.getStackLimit();
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment,
+ Position positionAtIPDChange, LayoutManager restartAtLM) {
- LayoutContext childLC = new LayoutContext(0);
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setRefIPD(context.getRefIPD());
- childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
-
- // get elements from curLM
- returnedList = curLM.getNextKnuthElements(childLC, alignment);
- //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
- if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
- context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
- childLC.clearKeepWithPreviousPending();
+ List elements = new LinkedList();
+
+ LayoutManager currentChildLM = positionAtIPDChange.getLM();
+ if (currentChildLM == null) {
+ throw new IllegalStateException(
+ "Cannot find layout manager from where to re-start layout after IPD change");
+ }
+ if (restartAtLM != null && restartAtLM.getParent() == this) {
+ currentChildLM = restartAtLM;
+ setCurrentChildLM(currentChildLM);
+ currentChildLM.reset();
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
}
+ } else {
+ Stack lmStack = new Stack();
+ while (currentChildLM.getParent() != this) {
+ lmStack.push(currentChildLM);
+ currentChildLM = currentChildLM.getParent();
+ }
+ setCurrentChildLM(currentChildLM);
+ if (addChildElements(elements, currentChildLM, context, alignment, lmStack,
+ positionAtIPDChange, restartAtLM) != null) {
+ return elements;
+ }
+ }
- // "wrap" the Position inside each element
- List tempList = returnedList;
- returnedList = new LinkedList();
- wrapPositionElements(tempList, returnedList);
-
- if (returnedList.size() == 1
- && ElementListUtils.endsWithForcedBreak(returnedList)) {
- // a descendant of this flow has break-before
- returnList.addAll(returnedList);
- SpaceResolver.resolveElementList(returnList);
- return returnList;
- } else if (returnedList.size() > 0) {
- if (returnList.size() > 0
- && !ElementListUtils.startsWithForcedBreak(returnedList)) {
- addInBetweenBreak(returnList, context, childLC);
- }
- returnList.addAll(returnedList);
- if (ElementListUtils.endsWithForcedBreak(returnList)) {
- if (curLM.isFinished() && !hasNextChildLM()) {
- //If the layout manager is finished at this point, the pending
- //marks become irrelevant.
- childLC.clearPendingMarks();
- //setFinished(true);
- break;
- }
- // a descendant of this flow has break-after
- SpaceResolver.resolveElementList(returnList);
- return returnList;
- }
+ while ((currentChildLM = getChildLM()) != null) {
+ currentChildLM.reset(); // TODO won't work with forced breaks
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
}
+ }
+
+ SpaceResolver.resolveElementList(elements);
+ setFinished(true);
+
+ assert !elements.isEmpty();
+ return elements;
+ }
- //Propagate and clear
- context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
- childLC.clearKeepWithNextPending();
+ private List addChildElements(List elements, LayoutManager childLM, LayoutContext context,
+ int alignment) {
+ return addChildElements(elements, childLM, context, alignment, null, null, null);
+ }
- context.updateKeepWithNextPending(getKeepWithNextStrength());
+ private List addChildElements(List elements, LayoutManager childLM, LayoutContext context,
+ int alignment, Stack lmStack, Position position, LayoutManager restartAtLM) {
+ if (handleSpanChange(childLM, elements, context)) {
+ SpaceResolver.resolveElementList(elements);
+ return elements;
}
- SpaceResolver.resolveElementList(returnList);
- setFinished(true);
+ LayoutContext childLC = new LayoutContext(0);
+ List childrenElements = getNextChildElements(childLM, context, childLC, alignment, lmStack,
+ position, restartAtLM);
+ if (elements.isEmpty()) {
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ }
+ if (!elements.isEmpty()
+ && !ElementListUtils.startsWithForcedBreak(childrenElements)) {
+ addInBetweenBreak(elements, context, childLC);
+ }
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+
+ elements.addAll(childrenElements);
- if (returnList.size() > 0) {
- return returnList;
+ if (ElementListUtils.endsWithForcedBreak(elements)) {
+ // a descendant of this flow has break-before or break-after
+ if (childLM.isFinished() && !hasNextChildLM()) {
+ setFinished(true);
+ }
+ SpaceResolver.resolveElementList(elements);
+ return elements;
+ }
+ return null;
+ }
+
+ private boolean handleSpanChange(LayoutManager childLM, List elements, LayoutContext context) {
+ int span = EN_NONE;
+ int disableColumnBalancing = EN_FALSE;
+ if (childLM instanceof BlockLayoutManager) {
+ span = ((BlockLayoutManager)childLM).getBlockFO().getSpan();
+ disableColumnBalancing = ((BlockLayoutManager) childLM).getBlockFO()
+ .getDisableColumnBalancing();
+ } else if (childLM instanceof BlockContainerLayoutManager) {
+ span = ((BlockContainerLayoutManager)childLM).getBlockContainerFO().getSpan();
+ disableColumnBalancing = ((BlockContainerLayoutManager) childLM).getBlockContainerFO()
+ .getDisableColumnBalancing();
+ }
+
+ int currentSpan = context.getCurrentSpan();
+ if (currentSpan != span) {
+ if (span == EN_ALL) {
+ context.setDisableColumnBalancing(disableColumnBalancing);
+ }
+ log.debug("span change from " + currentSpan + " to " + span);
+ context.signalSpanChange(span);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private List getNextChildElements(LayoutManager childLM, LayoutContext context,
+ LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition,
+ LayoutManager restartLM) {
+ childLC.setStackLimitBP(context.getStackLimitBP());
+ childLC.setRefIPD(context.getRefIPD());
+ childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
+
+ List childrenElements;
+ if (lmStack == null) {
+ childrenElements = childLM.getNextKnuthElements(childLC, alignment);
} else {
- return null;
+ childrenElements = childLM.getNextKnuthElements(childLC,
+ alignment, lmStack, restartPosition, restartLM);
}
+ assert !childrenElements.isEmpty();
+
+ // "wrap" the Position inside each element
+ List tempList = childrenElements;
+ childrenElements = new LinkedList();
+ wrapPositionElements(tempList, childrenElements);
+ return childrenElements;
}
/**
@@ -203,18 +246,18 @@
}
/** {@inheritDoc} */
- public int getKeepTogetherStrength() {
- return KEEP_AUTO;
+ public Keep getKeepTogether() {
+ return Keep.KEEP_AUTO;
}
/** {@inheritDoc} */
- public int getKeepWithNextStrength() {
- return KEEP_AUTO;
+ public Keep getKeepWithNext() {
+ return Keep.KEEP_AUTO;
}
/** {@inheritDoc} */
- public int getKeepWithPreviousStrength() {
- return KEEP_AUTO;
+ public Keep getKeepWithPrevious() {
+ return Keep.KEEP_AUTO;
}
/** {@inheritDoc} */
@@ -352,5 +395,10 @@
return getCurrentPV().getBodyRegion().getBPD();
}
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
+
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java Fri Sep 18 17:10:42 2009
@@ -92,18 +92,18 @@
}
/** {@inheritDoc} */
- public int getKeepTogetherStrength() {
- return getParentKeepTogetherStrength();
+ public Keep getKeepTogether() {
+ return getParentKeepTogether();
}
/** {@inheritDoc} */
- public int getKeepWithNextStrength() {
- return KEEP_AUTO;
+ public Keep getKeepWithNext() {
+ return Keep.KEEP_AUTO;
}
/** {@inheritDoc} */
- public int getKeepWithPreviousStrength() {
- return KEEP_AUTO;
+ public Keep getKeepWithPrevious() {
+ return Keep.KEEP_AUTO;
}
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java Fri Sep 18 17:10:42 2009
@@ -57,16 +57,12 @@
return true;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean canAppendSequence(KnuthSequence sequence) {
return sequence.isInlineSequence() && !isClosed;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean appendSequence(KnuthSequence sequence) {
if (!canAppendSequence(sequence)) {
return false;
@@ -83,18 +79,14 @@
return true;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
return appendSequence(sequence);
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public KnuthSequence endSequence() {
if (!isClosed) {
add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java Fri Sep 18 17:10:42 2009
@@ -45,7 +45,7 @@
public static final int FLAGGED_PENALTY = 50;
private int penalty;
- private boolean bFlagged;
+ private boolean isFlagged;
private int breakClass = -1;
/**
@@ -55,12 +55,12 @@
* @param p the penalty value of this penalty
* @param f is this penalty flagged?
* @param pos the Position stored in this penalty
- * @param bAux is this penalty auxiliary?
+ * @param isAuxiliary is this penalty auxiliary?
*/
- public KnuthPenalty(int w, int p, boolean f, Position pos, boolean bAux) {
- super(w, pos, bAux);
+ public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) {
+ super(w, pos, isAuxiliary);
penalty = p;
- bFlagged = f;
+ isFlagged = f;
}
/**
@@ -69,18 +69,37 @@
* @param w the width of this penalty
* @param p the penalty value of this penalty
* @param f is this penalty flagged?
- * @param iBreakClass the break class of this penalty (one of
+ * @param breakClass the break class of this penalty (one of
* {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
* {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
* @param pos the Position stored in this penalty
- * @param bAux is this penalty auxiliary?
+ * @param isAuxiliary is this penalty auxiliary?
*/
public KnuthPenalty(int w, int p, boolean f,
- int iBreakClass, Position pos, boolean bAux) {
- super(w, pos, bAux);
- penalty = p;
- bFlagged = f;
- breakClass = iBreakClass;
+ int breakClass, Position pos, boolean isAuxiliary) {
+ this(w, p, f, pos, isAuxiliary);
+ this.breakClass = breakClass;
+ }
+
+ private static String getBreakClassName(int breakClass) {
+ return AbstractBreaker.getBreakClassName(breakClass);
+ }
+
+ /**
+ * Get the penalty's value as a {@code java.lang.String}.
+ * (Mainly used in {@code toString()} methods, to improve readability
+ * of the trace logs.)
+ *
+ * @param penaltyValue the penalty value
+ * @return the penalty value as a {@code java.lang.String}
+ */
+ protected static String valueOf(int penaltyValue) {
+ String result = (penaltyValue < 0) ? "-" : "";
+ int tmpValue = Math.abs(penaltyValue);
+ result += (tmpValue == KnuthElement.INFINITE)
+ ? "INFINITE"
+ : String.valueOf(tmpValue);
+ return result;
}
/** {@inheritDoc} */
@@ -105,7 +124,7 @@
/** @return true is this penalty is a flagged one. */
public boolean isFlagged() {
- return bFlagged;
+ return isFlagged;
}
/** {@inheritDoc} */
@@ -121,14 +140,6 @@
return breakClass;
}
- /**
- * Sets the break class for this penalty.
- * @param cl the break class (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE, EN_ODD_PAGE)
- */
- public void setBreakClass(int cl) {
- this.breakClass = cl;
- }
-
/** {@inheritDoc} */
public String toString() {
StringBuffer sb = new StringBuffer(64);
@@ -137,39 +148,22 @@
}
sb.append("penalty");
sb.append(" p=");
- if (getP() < 0) {
- sb.append("-");
- }
- if (Math.abs(getP()) == INFINITE) {
- sb.append("INFINITE");
- } else {
- sb.append(getP());
- }
- if (isFlagged()) {
+ sb.append(valueOf(this.penalty));
+ if (this.isFlagged) {
sb.append(" [flagged]");
}
sb.append(" w=");
sb.append(getW());
if (isForcedBreak()) {
- sb.append(" (forced break");
- switch (getBreakClass()) {
- case Constants.EN_PAGE:
- sb.append(", page");
- break;
- case Constants.EN_COLUMN:
- sb.append(", column");
- break;
- case Constants.EN_EVEN_PAGE:
- sb.append(", even page");
- break;
- case Constants.EN_ODD_PAGE:
- sb.append(", odd page");
- break;
- default:
- }
- sb.append(")");
+ sb.append(" (forced break, ")
+ .append(getBreakClassName(this.breakClass))
+ .append(")");
+ } else if (this.penalty >= 0 && this.breakClass != -1) {
+ //penalty corresponding to a keep constraint
+ sb.append(" (keep constraint, ")
+ .append(getBreakClassName(this.breakClass))
+ .append(")");
}
return sb.toString();
}
-
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthSequence.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthSequence.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/KnuthSequence.java Fri Sep 18 17:10:42 2009
@@ -19,6 +19,8 @@
package org.apache.fop.layoutmgr;
+import org.apache.fop.util.ListUtil;
+
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
@@ -26,9 +28,6 @@
/**
* Represents a list of Knuth elements.
*/
-/**
- *
- */
public abstract class KnuthSequence extends ArrayList {
/**
* Creates a new and empty list.
@@ -132,11 +131,9 @@
* @return the last element of this sequence.
*/
public ListElement getLast() {
- int idx = size();
- if (idx == 0) {
- return null;
- }
- return (ListElement) get(idx - 1);
+ return (isEmpty()
+ ? null
+ : (ListElement) ListUtil.getLast(this));
}
/**
@@ -144,11 +141,9 @@
* @return the removed element.
*/
public ListElement removeLast() {
- int idx = size();
- if (idx == 0) {
- return null;
- }
- return (ListElement) remove(idx - 1);
+ return (isEmpty()
+ ? null
+ : (ListElement) ListUtil.removeLast(this));
}
/**
@@ -156,7 +151,45 @@
* @return the element at index index.
*/
public ListElement getElement(int index) {
- return (ListElement) get(index);
+ return (index >= size() || index < 0)
+ ? null
+ : (ListElement) get(index);
+ }
+
+ /** @return the position index of the first box in this sequence */
+ protected int getFirstBoxIndex() {
+ if (isEmpty()) {
+ return -1;
+ } else {
+ return getFirstBoxIndex(0);
+ }
+ }
+
+ /**
+ * Get the position index of the first box in this sequence,
+ * starting at the given index. If there is no box after the
+ * passed {@code startIndex}, the starting index itself is returned.
+ * @param startIndex the starting index for the lookup
+ * @return the absolute position index of the next box element
+ */
+ protected int getFirstBoxIndex(int startIndex) {
+ if (isEmpty() || startIndex < 0 || startIndex >= size()) {
+ return -1;
+ } else {
+ ListElement element = null;
+ int posIndex = startIndex;
+ int lastIndex = size();
+ while (posIndex < lastIndex
+ && !(element = getElement(posIndex)).isBox()) {
+ posIndex++;
+ }
+ if (posIndex != startIndex
+ && element.isBox()) {
+ return posIndex - 1;
+ } else {
+ return startIndex;
+ }
+ }
}
/**
@@ -165,4 +198,9 @@
*/
public abstract boolean isInlineSequence();
+ /** {@inheritDoc} */
+ public String toString() {
+ return "<KnuthSequence " + super.toString() + ">";
+ }
+
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutContext.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutContext.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutContext.java Fri Sep 18 17:10:42 2009
@@ -78,15 +78,6 @@
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimitBP;
- /**
- * Total available stacking dimension for a "galley-level" layout
- * manager in inline-progression-direction. It is passed by the
- * parent LM. For LineLM, the block LM determines this based on
- * indent properties.
- * These LM <b>may</b> wish to pass this information down to lower
- * level LM to allow them to optimize returned break possibilities.
- */
- private MinOptMax stackLimitIP;
/** to keep track of spanning in multi-column layout */
private int currentSpan = Constants.NOT_SET;
@@ -145,8 +136,8 @@
private int breakBefore;
private int breakAfter;
- private int pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
- private int pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
+ private Keep pendingKeepWithNext = Keep.KEEP_AUTO;
+ private Keep pendingKeepWithPrevious = Keep.KEEP_AUTO;
private int disableColumnBalancing;
@@ -158,7 +149,7 @@
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
this.writingMode = parentLC.writingMode;
- setStackLimitsFrom(parentLC);
+ setStackLimitBP(parentLC.getStackLimitBP());
this.leadingSpace = parentLC.leadingSpace; //???
this.trailingSpace = parentLC.trailingSpace; //???
this.hyphContext = parentLC.hyphContext;
@@ -183,7 +174,6 @@
this.flags = flags;
this.refIPD = 0;
stackLimitBP = new MinOptMax(0);
- stackLimitIP = new MinOptMax(0);
leadingSpace = null;
trailingSpace = null;
}
@@ -237,7 +227,7 @@
* Returns the strength of a keep-with-next currently pending.
* @return the keep-with-next strength
*/
- public int getKeepWithNextPending() {
+ public Keep getKeepWithNextPending() {
return this.pendingKeepWithNext;
}
@@ -245,7 +235,7 @@
* Returns the strength of a keep-with-previous currently pending.
* @return the keep-with-previous strength
*/
- public int getKeepWithPreviousPending() {
+ public Keep getKeepWithPreviousPending() {
return this.pendingKeepWithPrevious;
}
@@ -253,14 +243,14 @@
* Clears any pending keep-with-next strength.
*/
public void clearKeepWithNextPending() {
- this.pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
+ this.pendingKeepWithNext = Keep.KEEP_AUTO;
}
/**
* Clears any pending keep-with-previous strength.
*/
public void clearKeepWithPreviousPending() {
- this.pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
+ this.pendingKeepWithPrevious = Keep.KEEP_AUTO;
}
/**
@@ -273,18 +263,18 @@
/**
* Updates the currently pending keep-with-next strength.
- * @param strength the new strength to consider
+ * @param keep the new strength to consider
*/
- public void updateKeepWithNextPending(int strength) {
- this.pendingKeepWithNext = Math.max(this.pendingKeepWithNext, strength);
+ public void updateKeepWithNextPending(Keep keep) {
+ this.pendingKeepWithNext = this.pendingKeepWithNext.compare(keep);
}
/**
* Updates the currently pending keep-with-previous strength.
- * @param strength the new strength to consider
+ * @param keep the new strength to consider
*/
- public void updateKeepWithPreviousPending(int strength) {
- this.pendingKeepWithPrevious = Math.max(this.pendingKeepWithPrevious, strength);
+ public void updateKeepWithPreviousPending(Keep keep) {
+ this.pendingKeepWithPrevious = this.pendingKeepWithPrevious.compare(keep);
}
/**
@@ -292,7 +282,7 @@
* @return true if a keep-with-next constraint is pending
*/
public boolean isKeepWithNextPending() {
- return getKeepWithNextPending() != BlockLevelLayoutManager.KEEP_AUTO;
+ return !getKeepWithNextPending().isAuto();
}
/**
@@ -300,7 +290,7 @@
* @return true if a keep-with-previous constraint is pending
*/
public boolean isKeepWithPreviousPending() {
- return getKeepWithPreviousPending() != BlockLevelLayoutManager.KEEP_AUTO;
+ return !getKeepWithPreviousPending().isAuto();
}
public void setLeadingSpace(SpaceSpecifier space) {
@@ -398,31 +388,6 @@
}
/**
- * Sets the stack limit in inline-progression-dimension.
- * @param limit the stack limit
- */
- public void setStackLimitIP(MinOptMax limit) {
- stackLimitIP = limit;
- }
-
- /**
- * Returns the stack limit in inline-progression-dimension.
- * @return the stack limit
- */
- public MinOptMax getStackLimitIP() {
- return stackLimitIP;
- }
-
- /**
- * Sets (Copies) the stack limits in both directions from another layout context.
- * @param context the layout context to take the values from
- */
- public void setStackLimitsFrom(LayoutContext context) {
- setStackLimitBP(context.getStackLimitBP());
- setStackLimitIP(context.getStackLimitIP());
- }
-
- /**
* Sets the inline-progression-dimension of the nearest ancestor reference area.
*/
public void setRefIPD(int ipd) {
@@ -662,8 +627,6 @@
return "Layout Context:"
+ "\nStack Limit BPD: \t"
+ (getStackLimitBP() == null ? "null" : getStackLimitBP().toString())
- + "\nStack Limit IPD: \t"
- + (getStackLimitIP() == null ? "null" : getStackLimitIP().toString())
+ "\nTrailing Space: \t"
+ (getTrailingSpace() == null ? "null" : getTrailingSpace().toString())
+ "\nLeading Space: \t"
@@ -677,9 +640,8 @@
+ "\nStarts New Area: \t" + startsNewArea()
+ "\nIs Last Area: \t" + isLastArea()
+ "\nTry Hyphenate: \t" + tryHyphenate()
- + "\nKeeps: \t[keep-with-next=" + KeepUtil.keepStrengthToString(getKeepWithNextPending())
- + "][keep-with-previous="
- + KeepUtil.keepStrengthToString(getKeepWithPreviousPending()) + "] pending"
+ + "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending()
+ + "][keep-with-previous=" + getKeepWithPreviousPending() + "] pending"
+ "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
+ (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutManager.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LayoutManager.java Fri Sep 18 17:10:42 2009
@@ -20,6 +20,7 @@
package org.apache.fop.layoutmgr;
import java.util.List;
+import java.util.Stack;
import org.apache.fop.area.Area;
import org.apache.fop.datatypes.PercentBaseContext;
@@ -219,4 +220,36 @@
* @return the same Position but with a position index
*/
Position notifyPos(Position pos);
+
+ /**
+ * Re-initializes this layout manager in order to re-generate its Knuth
+ * elements according to a new IPD value.
+ */
+ void reset();
+
+ /**
+ * Returns {@code true} if this layout manager is able to re-generate its
+ * Knuth elements after an IPD change.
+ *
+ * @return {@code true} if this layout manager can be restarted after an IPD
+ * change
+ */
+ boolean isRestartable();
+
+ /**
+ * Returns an updated list of Knuth elements corresponding to this layout
+ * manager, after a change of IPD has been detected.
+ *
+ * @param context the layout context
+ * @param alignment the alignment
+ * @param lmStack the stack of LMs that are active at the IPD change
+ * @param positionAtIPDChange the position corresponding to the element
+ * finishing the page before the IPD change
+ * @param restartAtLM if not null, the layout manager from which to restart.
+ * That is, the IPD change occurs between two block elements and not inside
+ * a paragraph
+ * @return an updated list of elements, taking the new IPD into account
+ */
+ List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position positionAtIPDChange, LayoutManager restartAtLM);
}
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LeafPosition.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LeafPosition.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LeafPosition.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/LeafPosition.java Fri Sep 18 17:10:42 2009
@@ -21,15 +21,20 @@
public class LeafPosition extends Position {
- private int iLeafPos;
+ private int leafPos;
public LeafPosition(LayoutManager lm, int pos) {
super(lm);
- iLeafPos = pos;
+ leafPos = pos;
+ }
+
+ public LeafPosition(LayoutManager layoutManager, int pos, int index) {
+ super(layoutManager, index);
+ leafPos = pos;
}
public int getLeafPos() {
- return iLeafPos;
+ return leafPos;
}
public boolean generatesAreas() {
Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/Page.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/Page.java?rev=816718&r1=816717&r2=816718&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/Page.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/layoutmgr/Page.java Fri Sep 18 17:10:42 2009
@@ -19,7 +19,7 @@
package org.apache.fop.layoutmgr;
-import java.awt.geom.Rectangle2D;
+import java.awt.Rectangle;
import org.apache.fop.area.PageViewport;
import org.apache.fop.fo.pagination.SimplePageMaster;
@@ -54,7 +54,7 @@
* @param pageNumberStr the page number (as a String)
* @param blank true if this is a blank page
*/
- public Page(Rectangle2D viewArea, int pageNumber, String pageNumberStr, boolean blank) {
+ public Page(Rectangle viewArea, int pageNumber, String pageNumberStr, boolean blank) {
this.spm = null;
this.pageViewport = new PageViewport(viewArea, pageNumber, pageNumberStr, null, blank);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org