public List getNextKnuthElements()

in fop-core/src/main/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java [263:426]


    public List<KnuthSequence> getNextKnuthElements(
        LayoutContext context, int alignment) {
        LayoutManager curLM;

        // the list returned by child LM
        List<KnuthSequence> returnedList;

        // the list which will be returned to the parent LM
        List<KnuthSequence> returnList = new LinkedList<KnuthSequence>();
        KnuthSequence lastSequence = null;

        if (fobj instanceof Title) {
            alignmentContext = new AlignmentContext(font,
                                    lineHeight.getOptimum(this).getLength().getValue(this),
                                    context.getWritingMode());

        } else {
            alignmentContext = new AlignmentContext(font
                                    , lineHeight.getOptimum(this).getLength().getValue(this)
                                    , alignmentAdjust
                                    , alignmentBaseline
                                    , baselineShift
                                    , dominantBaseline
                                    , context.getAlignmentContext());
        }

        childLC = LayoutContext.copyOf(context);
        childLC.setAlignmentContext(alignmentContext);

        if (context.startsNewArea()) {
            // First call to this LM in new parent "area", but this may
            // not be the first area created by this inline
            if (getSpaceStart() != null) {
                context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this));
            }
        }

        StringBuffer trace = new StringBuffer("InlineLM:");

        // We'll add the border to the first inline sequence created.
        // This flag makes sure we do it only once.
        boolean borderAdded = false;

        if (borderProps != null) {
            childLC.setLineStartBorderAndPaddingWidth(context.getLineStartBorderAndPaddingWidth()
                + borderProps.getPaddingStart(true, this)
                + borderProps.getBorderStartWidth(true)
             );
            childLC.setLineEndBorderAndPaddingWidth(context.getLineEndBorderAndPaddingWidth()
                + borderProps.getPaddingEnd(true, this)
                + borderProps.getBorderEndWidth(true)
             );
        }

        while ((curLM = getChildLM()) != null) {

            if (!(curLM instanceof InlineLevelLayoutManager)) {
                // A block LM
                // Leave room for start/end border and padding
                if (borderProps != null) {
                    childLC.setRefIPD(childLC.getRefIPD()
                            - borderProps.getPaddingStart(lastChildLM != null, this)
                            - borderProps.getBorderStartWidth(lastChildLM != null)
                            - borderProps.getPaddingEnd(hasNextChildLM(), this)
                            - borderProps.getBorderEndWidth(hasNextChildLM()));
                }
            }

            // get KnuthElements from curLM
            returnedList = curLM.getNextKnuthElements(childLC, alignment);
            if (returnList.isEmpty() && childLC.isKeepWithPreviousPending()) {
                childLC.clearKeepWithPreviousPending();
            }
            if (returnedList == null
                    || returnedList.isEmpty()) {
                // curLM returned null or an empty list, because it finished;
                // just iterate once more to see if there is another child
                continue;
            }

            if (curLM instanceof InlineLevelLayoutManager) {
                context.clearKeepWithNextPending();
                // "wrap" the Position stored in each element of returnedList
                for (KnuthSequence sequence : returnedList) {
                    sequence.wrapPositions(this);
                }
                int insertionStartIndex = 0;
                if (lastSequence != null
                        && lastSequence.appendSequenceOrClose(returnedList.get(0))) {
                    insertionStartIndex = 1;
                }
                // add border and padding to the first complete sequence of this LM
                if (!borderAdded && !returnedList.isEmpty()) {
                    addKnuthElementsForBorderPaddingStart(returnedList.get(0));
                    borderAdded = true;
                }
                for (Iterator<KnuthSequence> iter = returnedList.listIterator(insertionStartIndex);
                        iter.hasNext();) {
                    returnList.add(iter.next());
                }
            } else { // A block LM
                BlockKnuthSequence sequence = new BlockKnuthSequence(returnedList);
                sequence.wrapPositions(this);
                boolean appended = false;
                if (lastSequence != null) {
                    if (lastSequence.canAppendSequence(sequence)) {
                        BreakElement bk = new BreakElement(new Position(this), 0, context);
                        boolean keepTogether = (mustKeepTogether()
                                                || context.isKeepWithNextPending()
                                                || childLC.isKeepWithPreviousPending());
                        appended = lastSequence.appendSequenceOrClose(sequence, keepTogether, bk);
                    } else {
                        lastSequence.endSequence();
                    }
                }
                if (!appended) {
                    // add border and padding to the first complete sequence of this LM
                    if (!borderAdded) {
                        addKnuthElementsForBorderPaddingStart(sequence);
                        borderAdded = true;
                    }
                    returnList.add(sequence);
                }
                // propagate and clear
                context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
                childLC.clearKeepsPending();
            }
            lastSequence = ListUtil.getLast(returnList);
            lastChildLM = curLM;
            // the context used to create this childLC above was applied a LayoutContext.SUPPRESS_BREAK_BEFORE
            // in the getNextChildElements() method of the parent BlockLayoutManger; as a consequence all
            // line breaks in blocks nested inside the inline associated with this ILM are being supressed;
            // here we revert that supression; we do not need to do that for the first element since that
            // is handled by the getBreakBefore() method of the wrapping BlockStackingLayoutManager.
            // Note: this fix seems to work but is far from being the ideal way to do this
            childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE, false);
        }

        if (lastSequence != null) {
            addKnuthElementsForBorderPaddingEnd(lastSequence);
        }

        setFinished(true);
        log.trace(trace);

        if (returnList.isEmpty()) {
            /*
             * if the FO itself is empty, but has an id specified
             * or associated fo:markers, then we still need a dummy
             * sequence to register its position in the area tree
             */
            if (fobj.hasId() || fobj.hasMarkers()) {
                InlineKnuthSequence emptySeq = new InlineKnuthSequence();
                emptySeq.add(new KnuthInlineBox(
                                0,
                                alignmentContext,
                                notifyPos(getAuxiliaryPosition()),
                                true));
                returnList.add(emptySeq);
            }
        }

        return returnList.isEmpty() ? null : returnList;
    }