public List getNextKnuthElements()

in fop-core/src/main/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java [246:382]


    public List<ListElement> 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;
    }