View | Details | Raw Unified | Return to bug 44328
Collapse All | Expand All

(-)src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (-7 / +90 lines)
Lines 66-71 Link Here
66
    private MinOptMax effSpaceBefore;
66
    private MinOptMax effSpaceBefore;
67
    private MinOptMax effSpaceAfter;
67
    private MinOptMax effSpaceAfter;
68
68
69
    private int orphans = 2;
70
    private int widows = 2;
71
69
    /**
72
    /**
70
     * Creates a new BlockLayoutManager.
73
     * Creates a new BlockLayoutManager.
71
     * @param inBlock the block FO object to create the layout manager for.
74
     * @param inBlock the block FO object to create the layout manager for.
Lines 97-102 Link Here
97
                                    .getOptimum(this).getLength().getValue(this);
100
                                    .getOptimum(this).getLength().getValue(this);
98
        adjustedSpaceAfter = fo.getCommonMarginBlock().spaceAfter.getSpace()
101
        adjustedSpaceAfter = fo.getCommonMarginBlock().spaceAfter.getSpace()
99
                                    .getOptimum(this).getLength().getValue(this);
102
                                    .getOptimum(this).getLength().getValue(this);
103
        orphans = fo.getOrphans();
104
        widows = fo.getWidows();
100
    }
105
    }
101
106
102
    /** {@inheritDoc} */
107
    /** {@inheritDoc} */
Lines 110-119 Link Here
110
    public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
115
    public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
111
            Position restartPosition, LayoutManager restartAtLM) {
116
            Position restartPosition, LayoutManager restartAtLM) {
112
        resetSpaces();
117
        resetSpaces();
113
        return super.getNextKnuthElements(
118
119
        List<ListElement> contentList = super.getNextKnuthElements(
114
                context, alignment, lmStack, restartPosition, restartAtLM);
120
                context, alignment, lmStack, restartPosition, restartAtLM);
115
    }
121
122
        if (!this.hasNextChildLM()) {
123
            // handle widows
124
            int boxCount = 0, index = contentList.size();
125
            ListElement current;
126
            for (ListIterator<ListElement> it = contentList.listIterator(contentList.size());
127
                    it.hasPrevious();) {
128
                current = it.previous();
129
                index--;
130
                if (current.isBox() && !((KnuthBox) current).isAuxiliary()) {
131
                    // non-auxiliary box => assume a 'line' and increase boxCount
132
                    boxCount++;
133
                    if (boxCount >= widows) {
134
                        break;
135
                    }
136
                }
137
            }
138
            if (index <= (contentList.size() - boxCount)) {
139
                ElementListUtils.removeLegalBreaks(
140
                        contentList.subList(index, contentList.size()));
141
            }
142
        }
116
143
144
        return contentList;
145
    }
146
117
    /**
147
    /**
118
     * Overridden to take into account that the childLM may be the block's
148
     * Overridden to take into account that the childLM may be the block's
119
     * {@link LineLayoutManager}.
149
     * {@link LineLayoutManager}.
Lines 132-156 Link Here
132
            // nop; will have been properly set by makeChildLayoutContext()
162
            // nop; will have been properly set by makeChildLayoutContext()
133
        }
163
        }
134
164
135
        if (childLM == this.childLMs.get(0)) {
165
        boolean isFirst = childLM == this.childLMs.get(0);
166
        if (isFirst) {
136
            childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
167
            childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
137
            //Handled already by the parent (break collapsing, see above)
168
            //Handled already by the parent (break collapsing, see above)
138
        }
169
        }
139
170
171
        List<ListElement> childElements;
140
        if (lmStack == null) {
172
        if (lmStack == null) {
141
            return childLM.getNextKnuthElements(childLC, alignment);
173
            childElements = childLM.getNextKnuthElements(childLC, alignment);
142
        } else {
174
        } else {
143
            if (childLM instanceof LineLayoutManager) {
175
            if (childLM instanceof LineLayoutManager) {
144
                assert (restartPosition instanceof LeafPosition);
176
                assert (restartPosition instanceof LeafPosition);
145
                return ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
177
                childElements = ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
146
                        (LeafPosition) restartPosition);
178
                        (LeafPosition) restartPosition);
147
            } else {
179
            } else {
148
                return childLM.getNextKnuthElements(childLC, alignment,
180
                childElements = childLM.getNextKnuthElements(childLC, alignment,
149
                        lmStack, restartPosition, restartAtLM);
181
                        lmStack, restartPosition, restartAtLM);
150
            }
182
            }
151
        }
183
        }
152
    }
184
185
        if (isFirst) {
186
            // handle orphans
187
            int boxCount = 0, endIndex = 0;
188
            ListElement current;
189
            for (ListIterator<ListElement> it = childElements.listIterator(); it.hasNext();) {
190
                current = it.next();
191
                endIndex++;
192
                if (current.isBox() && !((KnuthBox) current).isAuxiliary()) {
193
                    // non-auxiliary box => assume a 'line' and increase boxCount
194
                    boxCount++;
195
                    if (boxCount >= orphans) {
196
                        break;
197
                    }
198
                }
199
            }
200
            if (endIndex > boxCount) {
201
                ElementListUtils.removeLegalBreaks(childElements.subList(0, endIndex));
202
            }
203
        }
153
204
205
        return childElements;
206
    }
207
208
    /**
209
     * Overridden to deal with a special case for the "orphans" property.
210
     * {@inheritDoc}
211
     */
212
    @Override
213
    protected void addInBetweenBreak(List<ListElement> contentList, LayoutContext parentLC, LayoutContext childLC) {
214
215
        if (this.childLMs.size() > 1 &&
216
                this.curChildLM == this.childLMs.get(1)) {
217
            // special case: second childLM; if the first childLM did not produce enough
218
            // lines to satisfy this LM's orphans constraint, avoid adding a break possibility
219
            int boxCount = 0;
220
            for (ListElement el : contentList) {
221
                if (el.isBox() && !((KnuthBox) el).isAuxiliary()) {
222
                    boxCount++;
223
                    if (boxCount >= orphans) {
224
                        break;
225
                    }
226
                }
227
            }
228
229
            if (boxCount < orphans) {
230
                return;
231
            }
232
        }
233
234
        super.addInBetweenBreak(contentList, parentLC, childLC);
235
    }
236
154
    private void resetSpaces() {
237
    private void resetSpaces() {
155
        this.discardBorderBefore = false;
238
        this.discardBorderBefore = false;
156
        this.discardBorderAfter = false;
239
        this.discardBorderAfter = false;
(-)src/java/org/apache/fop/layoutmgr/KnuthPenalty.java (+3 lines)
Lines 46-51 Link Here
46
    /** Dummy, zero-width penalty */
46
    /** Dummy, zero-width penalty */
47
    public static final KnuthPenalty DUMMY_ZERO_PENALTY
47
    public static final KnuthPenalty DUMMY_ZERO_PENALTY
48
            = new KnuthPenalty(0, 0, false, null, true);
48
            = new KnuthPenalty(0, 0, false, null, true);
49
    /** Dummy break inhibitor */
50
    public static final KnuthPenalty DUMMY_INFINITE_PENALTY
51
            = new KnuthPenalty(0, KnuthElement.INFINITE, false, null, true);
49
52
50
    private int penalty;
53
    private int penalty;
51
    private boolean penaltyFlagged;
54
    private boolean penaltyFlagged;
(-)src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (-4 / +1 lines)
Lines 918-927 Link Here
918
                for (int i = 0;
918
                for (int i = 0;
919
                        i < llPoss.getChosenLineCount();
919
                        i < llPoss.getChosenLineCount();
920
                        i++) {
920
                        i++) {
921
                    if (returnList.size() > 0
921
                    if (returnList.size() > 0 && i > 0) {
922
                            && i > 0 //if i==0 break generated above already
923
                            && i >= fobj.getOrphans()
924
                            && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
925
                        // penalty allowing a page break between lines
922
                        // penalty allowing a page break between lines
926
                        Keep keep = getKeepTogether();
923
                        Keep keep = getKeepTogether();
927
                        returnList.add(new BreakElement(
924
                        returnList.add(new BreakElement(
(-)src/java/org/apache/fop/layoutmgr/ElementListUtils.java (+54 lines)
Lines 133-138 Link Here
133
    }
133
    }
134
134
135
    /**
135
    /**
136
     * Removes all legal break points from the given {@code List<ListElement>}.
137
     * That is, this method:<br/>
138
     * <ul>
139
     *   <li>removes penalties in between two boxes</li>
140
     *   <li>converts other penalties to inhibit breaks</li>
141
     *   <li>converts glues following a box into auxiliary boxes
142
     *       or penalty-glue sequences</li>
143
     *
144
     * @param elements  the element list from which the breaks will be removed
145
     */
146
    public static void removeLegalBreaks(List<ListElement> elements) {
147
148
        ListElement current;
149
        boolean previousIsBox = false;
150
151
        for (ListIterator<ListElement> it = elements.listIterator(); it.hasNext();) {
152
153
            current = it.next();
154
155
            if (current.isBox()) {
156
                previousIsBox = true;
157
                continue;
158
            } else if (current.isGlue() && previousIsBox) {
159
                KnuthGlue glue = (KnuthGlue)current;
160
                if (glue.getStretch() == 0 && glue.getShrink() == 0) {
161
                    // non-stretchable glue => replace with a box of the same width
162
                    it.set(new KnuthBox(glue.getWidth(), glue.getPosition(), true));
163
                } else {
164
                    // stretchable glue => add break-inhibitor
165
                    it.previous();
166
                    it.add(KnuthPenalty.DUMMY_INFINITE_PENALTY);
167
                    it.next();
168
                }
169
            } else if (current.isPenalty() || current instanceof BreakElement
170
                        && !current.isForcedBreak()) {
171
                boolean nextIsBox = (it.hasNext() && it.next().isBox());
172
                it.previous();
173
                if (previousIsBox && nextIsBox) {
174
                    // penalty or BreakElement in between boxes => remove
175
                    it.previous();
176
                    it.remove();
177
                } else {
178
                    if (current.isPenalty()) {
179
                        ((KnuthPenalty)current).setPenalty(KnuthElement.INFINITE);
180
                    } else {
181
                        ((BreakElement)current).setPenaltyValue(KnuthElement.INFINITE);
182
                    }
183
                }
184
            }
185
            previousIsBox = false;
186
        }
187
    }
188
189
    /**
136
     * Calculates the content length of the given element list. Warning: It doesn't take any
190
     * Calculates the content length of the given element list. Warning: It doesn't take any
137
     * stretch and shrink possibilities into account.
191
     * stretch and shrink possibilities into account.
138
     * @param elems the element list
192
     * @param elems the element list

Return to bug 44328