]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Creating a combined list for label and body
authorLuca Furini <lfurini@apache.org>
Wed, 13 Apr 2005 16:25:24 +0000 (16:25 +0000)
committerLuca Furini <lfurini@apache.org>
Wed, 13 Apr 2005 16:25:24 +0000 (16:25 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_KnuthStylePageBreaking@198581 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java

index 9e75ccd13338e70cc3b35046679cacadaf065374..75bdc6c9f20d11eca768fde3c8f0ad7c09d1ef88 100644 (file)
@@ -32,6 +32,8 @@ import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.TraitSetter;
 import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthBox;
+import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.KnuthPossPosIter;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Block;
@@ -59,7 +61,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager {
     private Block curBlockArea = null;
 
     private LinkedList labelList = null;
-    private boolean labelAreasAdded = false;
+    private LinkedList bodyList = null;
 
     private static class StackingIter extends PositionIterator {
         StackingIter(Iterator parentIter) {
@@ -90,6 +92,37 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager {
         }
     }
 
+    private class ListItemPosition extends Position {
+        private int iLabelFirstIndex;
+        private int iLabelLastIndex;
+        private int iBodyFirstIndex;
+        private int iBodyLastIndex;
+
+        public ListItemPosition(LayoutManager lm, int labelFirst, int labelLast, int bodyFirst, int bodyLast) {
+            super(lm);
+            iLabelFirstIndex = labelFirst;
+            iLabelLastIndex = labelLast;
+            iBodyFirstIndex = bodyFirst;
+            iBodyLastIndex = bodyLast;
+        }
+        
+        public int getLabelFirstIndex() {
+            return iLabelFirstIndex;
+        }
+        
+        public int getLabelLastIndex() {
+            return iLabelLastIndex;
+        }
+
+        public int getBodyFirstIndex() {
+            return iBodyFirstIndex;
+        }
+        
+        public int getBodyLastIndex() {
+            return iBodyLastIndex;
+        }
+    }
+
     /**
      * Create a new list item layout manager.
      * @param node list-item to create the layout manager for
@@ -253,7 +286,10 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager {
         labelList = label.getNextKnuthElements(context, alignment);
 
         // body
-        LinkedList returnedList = body.getNextKnuthElements(context, alignment);
+        bodyList = body.getNextKnuthElements(context, alignment);
+
+        // create a combined list
+        LinkedList returnedList = getCombinedKnuthElementsForListItem(labelList, bodyList);
 
         // "wrap" the Position inside each element
         LinkedList tempList = returnedList;
@@ -270,6 +306,136 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager {
         return returnedList;
     }
 
+    private LinkedList getCombinedKnuthElementsForListItem(LinkedList labelElements,
+                                                           LinkedList bodyElements) {
+        //Copy elements to array lists to improve element access performance
+        List[] elementLists = {new ArrayList(labelElements),
+                               new ArrayList(bodyElements)};
+        int[] fullHeights = {calcItemHeightFromContents(elementLists[0]),
+                            calcItemHeightFromContents(elementLists[1])};
+        int[] partialHeights = {0, 0};
+        int[] start = {-1, -1};
+        int[] end = {-1, -1};
+
+        int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
+        int step;
+        int addedBoxHeight = 0;
+
+        LinkedList returnList = new LinkedList();
+        while ((step = getNextStep(elementLists, start, end, partialHeights))
+               > 0) {
+            // compute penalty height and box height
+            int penaltyHeight = step + getMaxRemainingHeight(fullHeights, partialHeights) - totalHeight;
+            int boxHeight = step - addedBoxHeight - penaltyHeight;
+
+            // add the new elements
+            addedBoxHeight += boxHeight;
+            ListItemPosition stepPosition = new ListItemPosition(this, start[0], end[0], start[1], end[1]);
+            returnList.add(new KnuthBox(boxHeight, stepPosition, false));
+            if (addedBoxHeight < totalHeight) {
+                returnList.add(new KnuthPenalty(penaltyHeight, 0, false, stepPosition, false));
+            }
+        }
+
+        return returnList;
+    }
+
+    private int calcItemHeightFromContents(List elements, int start, int end) {
+        ListIterator iter = elements.listIterator(start);
+        int count = end - start + 1;
+        int len = 0;
+        while (iter.hasNext()) {
+            KnuthElement el = (KnuthElement)iter.next();
+            if (el.isBox()) {
+                len += el.getW();
+            } else if (el.isGlue()) {
+                len += el.getW();
+            } else {
+                log.debug("Ignoring penalty: " + el);
+                //ignore penalties
+            }
+            count--;
+            if (count == 0) {
+                break;
+            }
+        }
+        return len;
+    }
+    
+    private int calcItemHeightFromContents(List elements) {
+        return calcItemHeightFromContents(elements, 0, elements.size() - 1);
+    }
+
+    private int getNextStep(List elementLists[], int[] start, int[] end, int[] partialHeights) {
+        // backup of partial heights
+        int backupHeights[] = {partialHeights[0], partialHeights[1]};
+
+        // set starting points
+        start[0] = end[0] + 1;
+        start[1] = end[1] + 1;
+
+        // get next possible sequence for label and body
+        int seqCount = 0;
+        for (int i = 0; i < start.length; i++) {
+            while (end[i] + 1 < elementLists[i].size()) {
+                end[i]++;
+                KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
+                if (el.isPenalty()) {
+                    if (el.getP() < KnuthElement.INFINITE) {
+                        //First legal break point
+                        break;
+                    }
+                } else if (el.isGlue()) {
+                    KnuthElement prev = (KnuthElement)elementLists[i].get(end[i] - 1);
+                    if (prev.isBox()) {
+                        //Second legal break point
+                        break;
+                    }
+                    partialHeights[i] += el.getW();
+                } else {
+                    partialHeights[i] += el.getW();
+                }
+            }
+            if (end[i] < start[i]) {
+                partialHeights[i] = backupHeights[i];
+            } else {
+                seqCount++;
+            }
+        }
+        if (seqCount == 0) {
+            return 0;
+        }
+        
+        // determine next step
+        int step;
+        if (backupHeights[0] == 0 && backupHeights[1] == 0) {
+            // this is the first step: choose the maximum increase, so that
+            // the smallest area in the first page will contain at least
+            // a label area and a body area
+            step = Math.max((end[0] >= start[0] ? partialHeights[0] : Integer.MIN_VALUE),
+                            (end[1] >= start[1] ? partialHeights[1] : Integer.MIN_VALUE));
+        } else {
+            // this is not the first step: choose the minimum increase
+            step = Math.min((end[0] >= start[0] ? partialHeights[0] : Integer.MAX_VALUE),
+                            (end[1] >= start[1] ? partialHeights[1] : Integer.MAX_VALUE));
+        }
+
+        // reset bigger-than-step sequences
+        for (int i = 0; i < partialHeights.length; i++) {
+            if (partialHeights[i] > step) {
+                partialHeights[i] = backupHeights[i];
+                end[i] = start[i] - 1;
+            }
+        }
+
+        return step;
+    }
+
+    private int getMaxRemainingHeight(int[] fullHeights, int[] partialHeights) {
+        return Math.max(fullHeights[0] - partialHeights[0],
+                        fullHeights[1] - partialHeights[1]);
+    }
+
     public LinkedList getChangedKnuthElements(List oldList, int alignment) {
 /*LF*/  //log.debug(" LILM.getChanged> label");
         // label
@@ -331,46 +497,56 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager {
 
         LayoutManager childLM = null;
         LayoutContext lc = new LayoutContext(0);
-        LayoutManager firstLM = null;
-        LayoutManager lastLM = null;
 
-        // create a new list; 
-        // add the label areas, if this is the first time addAreas() is called
-        LinkedList positionList = new LinkedList();
-        if (!labelAreasAdded) {
-            KnuthPossPosIter labelPosIter = new KnuthPossPosIter(labelList, 0, labelList.size());
-            while (labelPosIter.hasNext()) {
-                positionList.add((Position) labelPosIter.next());
-            }
-        }
         // "unwrap" the NonLeafPositions stored in parentIter
+        LinkedList positionList = new LinkedList();
         Position pos;
         while (parentIter.hasNext()) {
             pos = (Position) parentIter.next();
-            if (pos instanceof NonLeafPosition
-                && ((NonLeafPosition) pos).getPosition().getLM() != this) {
-                // pos was created by a child of this ListBlockLM
+            if (pos instanceof NonLeafPosition) {
+                // pos contains a ListItemPosition created by this ListBlockLM
                 positionList.add(((NonLeafPosition) pos).getPosition());
-                lastLM = ((NonLeafPosition) pos).getPosition().getLM();
-                if (firstLM == null) {
-                    firstLM = lastLM;
-                }
             }
         }
 
-        StackingIter childPosIter = new StackingIter(positionList.listIterator());
-        while ((childLM = childPosIter.getNextChildLM()) != null) {
-            // Add the block areas to Area
-            lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
-            lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
-            // reset the area height after adding the label areas
-            if (!labelAreasAdded && childLM == firstLM) {
-                curBlockArea.setBPD(0);
-                labelAreasAdded = true;
-            }
-            /* questo non e' correttissimo, bisogna avere due diversi valori per la label e il body */
+        // use the first and the last ListItemPosition to determine the 
+        // corresponding indexes in the original labelList and bodyList
+        int labelFirstIndex = ((ListItemPosition) positionList.getFirst()).getLabelFirstIndex();
+        int labelLastIndex = ((ListItemPosition) positionList.getLast()).getLabelLastIndex();
+        int bodyFirstIndex = ((ListItemPosition) positionList.getFirst()).getBodyFirstIndex();
+        int bodyLastIndex = ((ListItemPosition) positionList.getLast()).getBodyLastIndex();
+
+        // add label areas
+        if (labelFirstIndex <= labelLastIndex) {
+            KnuthPossPosIter labelIter = new KnuthPossPosIter(labelList, labelFirstIndex, labelLastIndex + 1);
+            lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
+            lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
+            // TO DO: use the right stack limit for the label
             lc.setStackLimit(layoutContext.getStackLimit());
-            childLM.addAreas(childPosIter, lc);
+            label.addAreas(labelIter, lc);
+        }
+
+        // reset the area bpd after adding the label areas and before adding the body areas
+        int savedBPD = 0;
+        if (labelFirstIndex <= labelLastIndex
+            && bodyFirstIndex <= bodyLastIndex) {
+            savedBPD = curBlockArea.getBPD();
+            curBlockArea.setBPD(0);
+        }
+
+        // add body areas
+        if (bodyFirstIndex <= bodyLastIndex) {
+            KnuthPossPosIter bodyIter = new KnuthPossPosIter(bodyList, bodyFirstIndex, bodyLastIndex + 1);
+            lc.setFlags(LayoutContext.FIRST_AREA, layoutContext.isFirstArea());
+            lc.setFlags(LayoutContext.LAST_AREA, layoutContext.isLastArea());
+            // TO DO: use the right stack limit for the body
+            lc.setStackLimit(layoutContext.getStackLimit());
+            body.addAreas(bodyIter, lc);
+        }
+
+        // after adding body areas, set the maximum area bpd
+        if (curBlockArea.getBPD() < savedBPD) {
+            curBlockArea.setBPD(savedBPD);
         }
 
         flush();