in fop-core/src/main/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java [246:382]
public List getNextKnuthElements(LayoutContext context, int alignment,
Stack lmStack, Position restartPosition, LayoutManager restartAtLM) {
isRestartAtLM = restartAtLM != null;
referenceIPD = context.getRefIPD();
updateContentAreaIPDwithOverconstrainedAdjust();
boolean isRestart = (lmStack != null);
boolean emptyStack = (!isRestart || lmStack.isEmpty());
List<ListElement> contentList = new LinkedList<ListElement>();
List<ListElement> elements = new LinkedList<ListElement>();
if (!breakBeforeServed(context, elements)) {
// if this FO has break-before specified, and it
// has not yet been processed, return now
return elements;
}
addFirstVisibleMarks(elements, context, alignment);
//Used to indicate a special break-after case when all content has already been generated.
BreakElement forcedBreakAfterLast = null;
LayoutContext childLC;
List<ListElement> childElements;
LayoutManager currentChildLM;
if (isRestart) {
if (emptyStack) {
assert restartAtLM != null && restartAtLM.getParent() == this;
currentChildLM = restartAtLM;
} else {
currentChildLM = (LayoutManager) lmStack.pop();
}
setCurrentChildLM(currentChildLM);
} else {
currentChildLM = getChildLM();
}
while (currentChildLM != null) {
childLC = makeChildLayoutContext(context);
if (!isRestart || emptyStack) {
if (isRestart) {
currentChildLM.reset(); // TODO won't work with forced breaks
}
childElements = getNextChildElements(currentChildLM, context, childLC, alignment,
null, null, null);
} else {
// restart && non-empty LM stack
childElements = getNextChildElements(currentChildLM, context, childLC, alignment,
lmStack, restartPosition, restartAtLM);
// once encountered, irrelevant for following child LMs
emptyStack = true;
}
if (contentList.isEmpty()) {
// propagate keep-with-previous up from the first child
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
}
// handle non-empty child
if (childElements != null && !childElements.isEmpty()) {
if (!contentList.isEmpty()
&& !ElementListUtils.startsWithForcedBreak(childElements)) {
// there is a block handled by prevLM before the one
// handled by curLM, and the one handled
// by the current LM does not begin with a break
addInBetweenBreak(contentList, context, childLC);
}
if (childElements.size() == 1
&& ElementListUtils.startsWithForcedBreak(childElements)) {
// a descendant of this block has break-before
if (currentChildLM.isFinished() && !hasNextChildLM()) {
// if there is no more content, make sure pending
// marks are cleared
forcedBreakAfterLast = (BreakElement) childElements.get(0);
context.clearPendingMarks();
// break without adding the child elements
break;
}
if (contentList.isEmpty()) {
// empty fo:block: zero-length box makes sure the IDs and/or markers
// are registered and borders/padding are painted.
elements.add(makeAuxiliaryZeroWidthBox());
}
// add the forced break
contentList.addAll(childElements);
// wrap position and return
wrapPositionElements(contentList, elements);
return elements;
} else {
// add all accumulated child elements
contentList.addAll(childElements);
if (ElementListUtils.endsWithForcedBreak(childElements)) {
// a descendant of this block has break-after
if (currentChildLM.isFinished() && !hasNextChildLM()) {
// if there is no more content, make sure any
// pending marks are cleared
forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
context.clearPendingMarks();
break;
}
//wrap positions and return
wrapPositionElements(contentList, elements);
return elements;
}
}
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
}
currentChildLM = getChildLM();
}
if (contentList.isEmpty()) {
if (forcedBreakAfterLast == null) {
// empty fo:block: zero-length box makes sure the IDs and/or markers
// are registered.
elements.add(makeAuxiliaryZeroWidthBox());
}
} else {
// wrap child positions
wrapPositionElements(contentList, elements);
}
addLastVisibleMarks(elements, context, alignment);
if (forcedBreakAfterLast == null) {
addKnuthElementsForBreakAfter(elements, context);
} else {
forcedBreakAfterLast.clearPendingMarks();
elements.add(forcedBreakAfterLast);
}
context.updateKeepWithNextPending(getKeepWithNext());
setFinished(true);
return elements;
}