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;
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) {
}
}
+ 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
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;
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
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();