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>&gt;= -1 &amp;&amp; &lt; 0  means that the break is wider than the line,
@@ -871,9 +1090,9 @@
      *        but within the maximum values of the glues.</li>
      *    <li>&gt; 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