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

(-)src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java (-6 / +6 lines)
Lines 415-432 Link Here
415
    }
415
    }
416
416
417
    /** {@inheritDoc} */
417
    /** {@inheritDoc} */
418
    public int getKeepTogetherStrength() {
418
    public Keep getKeepTogether() {
419
        return KEEP_AUTO;
419
        return Keep.KEEP_AUTO;
420
    }
420
    }
421
421
422
    /** {@inheritDoc} */
422
    /** {@inheritDoc} */
423
    public int getKeepWithNextStrength() {
423
    public Keep getKeepWithNext() {
424
        return KEEP_AUTO;
424
        return Keep.KEEP_AUTO;
425
    }
425
    }
426
426
427
    /** {@inheritDoc} */
427
    /** {@inheritDoc} */
428
    public int getKeepWithPreviousStrength() {
428
    public Keep getKeepWithPrevious() {
429
        return KEEP_AUTO;
429
        return Keep.KEEP_AUTO;
430
    }
430
    }
431
431
432
}
432
}
(-)src/java/org/apache/fop/layoutmgr/KeepUtil.java (-109 lines)
Lines 1-109 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
/* $Id$ */
19
20
package org.apache.fop.layoutmgr;
21
22
import org.apache.fop.fo.Constants;
23
import org.apache.fop.fo.properties.KeepProperty;
24
import org.apache.fop.fo.properties.Property;
25
26
/**
27
 * Utility class for working with keeps.
28
 */
29
public class KeepUtil {
30
31
    /**
32
     * Converts a keep property into an integer value.
33
     * <p>
34
     * Note: The conversion restricts the effectively available integer range by two values.
35
     * Integer.MIN_VALUE is used to represent the value "auto" and
36
     * Integer.MAX_VALUE is used to represebt the value "always".
37
     * @param keep the keep property
38
     * @return the keep value as an integer
39
     */
40
    public static int getKeepStrength(Property keep) {
41
        if (keep.isAuto()) {
42
            return BlockLevelLayoutManager.KEEP_AUTO;
43
        } else if (keep.getEnum() == Constants.EN_ALWAYS) {
44
            return BlockLevelLayoutManager.KEEP_ALWAYS;
45
        } else {
46
            return keep.getNumber().intValue();
47
        }
48
    }
49
50
    /**
51
     * Returns the combined block-level keep strength from a keep property.
52
     * <p>
53
     * Note: This is a temporary method to be used until it is possible to differentiate between
54
     * page and column keeps!
55
     * @param keep the keep property
56
     * @return the combined keep strength
57
     */
58
    public static int getCombinedBlockLevelKeepStrength(KeepProperty keep) {
59
        return Math.max(
60
                getKeepStrength(keep.getWithinPage()),
61
                getKeepStrength(keep.getWithinColumn()));
62
    }
63
64
    /**
65
     * Indicates whether a keep strength indicates a keep constraint.
66
     * @param strength the keep strength
67
     * @return true if the keep is not "auto"
68
     */
69
    public static boolean hasKeep(int strength) {
70
        return strength > BlockLevelLayoutManager.KEEP_AUTO;
71
    }
72
73
    /**
74
     * Returns the penalty value to be used for a certain keep strength.
75
     * <ul>
76
     *   <li>"auto": returns 0</li>
77
     *   <li>"always": returns KnuthElement.INFINITE</li>
78
     *   <li>otherwise: returns KnuthElement.INFINITE - 1</li>
79
     * </ul>
80
     * @param keepStrength the keep strength
81
     * @return the penalty value
82
     */
83
    public static int getPenaltyForKeep(int keepStrength) {
84
        if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) {
85
            return 0;
86
        }
87
        int penalty = KnuthElement.INFINITE;
88
        if (keepStrength < BlockLevelLayoutManager.KEEP_ALWAYS) {
89
            penalty--;
90
        }
91
        return penalty;
92
    }
93
94
    /**
95
     * Returns a string representation of a keep strength value.
96
     * @param keepStrength the keep strength
97
     * @return the string representation
98
     */
99
    public static String keepStrengthToString(int keepStrength) {
100
        if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) {
101
            return "auto";
102
        } else if (keepStrength == BlockLevelLayoutManager.KEEP_ALWAYS) {
103
            return "always";
104
        } else {
105
            return Integer.toString(keepStrength);
106
        }
107
    }
108
109
}
(-)src/java/org/apache/fop/layoutmgr/KnuthPenalty.java (-28 / +38 lines)
Lines 45-51 Link Here
45
    public static final int FLAGGED_PENALTY = 50;
45
    public static final int FLAGGED_PENALTY = 50;
46
46
47
    private int penalty;
47
    private int penalty;
48
    private boolean bFlagged;
48
    private boolean isFlagged;
49
    private int breakClass = -1;
49
    private int breakClass = -1;
50
50
51
    /**
51
    /**
Lines 55-66 Link Here
55
     * @param p the penalty value of this penalty
55
     * @param p the penalty value of this penalty
56
     * @param f is this penalty flagged?
56
     * @param f is this penalty flagged?
57
     * @param pos the Position stored in this penalty
57
     * @param pos the Position stored in this penalty
58
     * @param bAux is this penalty auxiliary?
58
     * @param isAuxiliary is this penalty auxiliary?
59
     */
59
     */
60
    public KnuthPenalty(int w, int p, boolean f, Position pos, boolean bAux) {
60
    public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) {
61
        super(w, pos, bAux);
61
        super(w, pos, isAuxiliary);
62
        penalty = p;
62
        penalty = p;
63
        bFlagged = f;
63
        isFlagged = f;
64
    }
64
    }
65
65
66
    /**
66
    /**
Lines 69-86 Link Here
69
     * @param w the width of this penalty
69
     * @param w the width of this penalty
70
     * @param p the penalty value of this penalty
70
     * @param p the penalty value of this penalty
71
     * @param f is this penalty flagged?
71
     * @param f is this penalty flagged?
72
     * @param iBreakClass the break class of this penalty (one of
72
     * @param breakClass the break class of this penalty (one of
73
     * {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
73
     * {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
74
     * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
74
     * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
75
     * @param pos the Position stored in this penalty
75
     * @param pos the Position stored in this penalty
76
     * @param bAux is this penalty auxiliary?
76
     * @param isAuxiliary is this penalty auxiliary?
77
     */
77
     */
78
    public KnuthPenalty(int w, int p, boolean f,
78
    public KnuthPenalty(int w, int p, boolean f,
79
            int iBreakClass, Position pos, boolean bAux) {
79
            int breakClass, Position pos, boolean isAuxiliary) {
80
        super(w, pos, bAux);
80
        this(w, p, f, pos, isAuxiliary);
81
        penalty = p;
81
        this.breakClass = breakClass;
82
        bFlagged = f;
83
        breakClass = iBreakClass;
84
    }
82
    }
85
83
86
    /** {@inheritDoc} */
84
    /** {@inheritDoc} */
Lines 105-118 Link Here
105
103
106
    /** @return true is this penalty is a flagged one. */
104
    /** @return true is this penalty is a flagged one. */
107
    public boolean isFlagged() {
105
    public boolean isFlagged() {
108
        return bFlagged;
106
        return isFlagged;
109
    }
107
    }
110
108
111
    /** {@inheritDoc} */
109
    /** {@inheritDoc} */
112
    public boolean isForcedBreak() {
110
    public boolean isForcedBreak() {
113
        return penalty == -KnuthElement.INFINITE;
111
        return (penalty == -KnuthElement.INFINITE);
114
    }
112
    }
115
113
114
    /** {@inheritDoc} */
115
    public int getType() {
116
        return PENALTY_TYPE;
117
    }
118
116
    /**
119
    /**
117
     * @return the break class of this penalty (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE,
120
     * @return the break class of this penalty (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE,
118
     * EN_ODD_PAGE)
121
     * EN_ODD_PAGE)
Lines 121-134 Link Here
121
        return breakClass;
124
        return breakClass;
122
    }
125
    }
123
126
124
    /**
125
     * Sets the break class for this penalty.
126
     * @param cl the break class (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE, EN_ODD_PAGE)
127
     */
128
    public void setBreakClass(int cl) {
129
        this.breakClass = cl;
130
    }
131
132
    /** {@inheritDoc} */
127
    /** {@inheritDoc} */
133
    public String toString() {
128
    public String toString() {
134
        StringBuffer sb = new StringBuffer(64);
129
        StringBuffer sb = new StringBuffer(64);
Lines 137-158 Link Here
137
        }
132
        }
138
        sb.append("penalty");
133
        sb.append("penalty");
139
        sb.append(" p=");
134
        sb.append(" p=");
140
        if (getP() < 0) {
135
        if (this.penalty < 0) {
141
            sb.append("-");
136
            sb.append("-");
142
        }
137
        }
143
        if (Math.abs(getP()) == INFINITE) {
138
        if (Math.abs(this.penalty) == INFINITE) {
144
            sb.append("INFINITE");
139
            sb.append("INFINITE");
145
        } else {
140
        } else {
146
            sb.append(getP());
141
            sb.append(this.penalty);
147
        }
142
        }
148
        if (isFlagged()) {
143
        if (this.isFlagged) {
149
            sb.append(" [flagged]");
144
            sb.append(" [flagged]");
150
        }
145
        }
151
        sb.append(" w=");
146
        sb.append(" w=");
152
        sb.append(getW());
147
        sb.append(getW());
153
        if (isForcedBreak()) {
148
        if (isForcedBreak()) {
154
            sb.append(" (forced break");
149
            sb.append(" (forced break");
155
            switch (getBreakClass()) {
150
            switch (this.breakClass) {
156
            case Constants.EN_PAGE:
151
            case Constants.EN_PAGE:
157
                sb.append(", page");
152
                sb.append(", page");
158
                break;
153
                break;
Lines 168-175 Link Here
168
            default:
163
            default:
169
            }
164
            }
170
            sb.append(")");
165
            sb.append(")");
166
        } else {
167
            sb.append(" (keep context: ");
168
            switch (this.breakClass) {
169
            case Constants.EN_PAGE:
170
                sb.append(" page)");
171
                break;
172
            case Constants.EN_COLUMN:
173
                sb.append(" column)");
174
                break;
175
            case Constants.EN_LINE:
176
                sb.append(" line)");
177
                break;
178
            default:
179
                sb.append(" auto)");
180
                break;
181
            }
171
        }
182
        }
172
        return sb.toString();
183
        return sb.toString();
173
    }
184
    }
174
175
}
185
}
(-)src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (-20 / +36 lines)
Lines 36-41 Link Here
36
import org.apache.fop.fo.Constants;
36
import org.apache.fop.fo.Constants;
37
import org.apache.fop.fo.flow.Block;
37
import org.apache.fop.fo.flow.Block;
38
import org.apache.fop.fo.properties.CommonHyphenation;
38
import org.apache.fop.fo.properties.CommonHyphenation;
39
import org.apache.fop.fo.properties.KeepProperty;
39
import org.apache.fop.fonts.Font;
40
import org.apache.fop.fonts.Font;
40
import org.apache.fop.fonts.FontInfo;
41
import org.apache.fop.fonts.FontInfo;
41
import org.apache.fop.fonts.FontTriplet;
42
import org.apache.fop.fonts.FontTriplet;
Lines 46-52 Link Here
46
import org.apache.fop.layoutmgr.BreakingAlgorithm;
47
import org.apache.fop.layoutmgr.BreakingAlgorithm;
47
import org.apache.fop.layoutmgr.ElementListObserver;
48
import org.apache.fop.layoutmgr.ElementListObserver;
48
import org.apache.fop.layoutmgr.InlineKnuthSequence;
49
import org.apache.fop.layoutmgr.InlineKnuthSequence;
49
import org.apache.fop.layoutmgr.KeepUtil;
50
import org.apache.fop.layoutmgr.Keep;
50
import org.apache.fop.layoutmgr.KnuthBlockBox;
51
import org.apache.fop.layoutmgr.KnuthBlockBox;
51
import org.apache.fop.layoutmgr.KnuthBox;
52
import org.apache.fop.layoutmgr.KnuthBox;
52
import org.apache.fop.layoutmgr.KnuthElement;
53
import org.apache.fop.layoutmgr.KnuthElement;
Lines 362-368 Link Here
362
            int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
363
            int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
363
            indent += (textAlign == Constants.EN_CENTER)
364
            indent += (textAlign == Constants.EN_CENTER)
364
                      ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
365
                      ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
365
            indent += (bestActiveNode.line == 1 && bFirst && isFirstInBlock) ? textIndent : 0;
366
            indent += (bestActiveNode.line == 1 && indentFirstPart && isFirstInBlock) ? textIndent : 0;
366
            double ratio = (textAlign == Constants.EN_JUSTIFY
367
            double ratio = (textAlign == Constants.EN_JUSTIFY
367
                || difference < 0 && -difference <= bestActiveNode.availableShrink)
368
                || difference < 0 && -difference <= bestActiveNode.availableShrink)
368
                        ? bestActiveNode.adjustRatio : 0;
369
                        ? bestActiveNode.adjustRatio : 0;
Lines 1054-1065 Link Here
1054
        for (int p = 0; p < knuthParagraphs.size(); p++) {
1055
        for (int p = 0; p < knuthParagraphs.size(); p++) {
1055
            // penalty between paragraphs
1056
            // penalty between paragraphs
1056
            if (p > 0) {
1057
            if (p > 0) {
1057
                int strength = getKeepTogetherStrength();
1058
                Keep keep = getKeepTogether();
1058
                int penalty = KeepUtil.getPenaltyForKeep(strength);
1059
                int penalty = keep.getPenalty();
1059
                if (penalty < KnuthElement.INFINITE) {
1060
                //if (penalty < KnuthElement.INFINITE) {
1060
                    returnList.add(new BreakElement(
1061
                    returnList.add(new BreakElement(
1061
                            new Position(this), penalty, context));
1062
                            new Position(this), penalty, keep.getContext(), context));
1062
                }
1063
                //}
1063
            }
1064
            }
1064
1065
1065
            LineLayoutPossibilities llPoss;
1066
            LineLayoutPossibilities llPoss;
Lines 1098-1109 Link Here
1098
                            && i >= fobj.getOrphans()
1099
                            && i >= fobj.getOrphans()
1099
                            && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
1100
                            && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
1100
                        // penalty allowing a page break between lines
1101
                        // penalty allowing a page break between lines
1101
                        int strength = getKeepTogetherStrength();
1102
                        Keep keep = getKeepTogether();
1102
                        int penalty = KeepUtil.getPenaltyForKeep(strength);
1103
                        int penalty = keep.getPenalty();
1103
                        if (penalty < KnuthElement.INFINITE) {
1104
                        //if (penalty < KnuthElement.INFINITE) {
1104
                            returnList.add(new BreakElement(
1105
                            returnList.add(new BreakElement(
1105
                                    returnPosition, penalty, context));
1106
                                    returnPosition, penalty, keep.getContext(), context));
1106
                        }
1107
                        //}
1107
                    }
1108
                    }
1108
                    int endIndex
1109
                    int endIndex
1109
                      = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
1110
                      = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
Lines 1283-1310 Link Here
1283
    }
1284
    }
1284
1285
1285
    /** {@inheritDoc} */
1286
    /** {@inheritDoc} */
1286
    public int getKeepTogetherStrength() {
1287
    public KeepProperty getKeepTogetherProperty() {
1287
        return ((BlockLevelLayoutManager) getParent()).getKeepTogetherStrength();
1288
        return ((BlockLevelLayoutManager) getParent()).getKeepTogetherProperty();
1288
    }
1289
    }
1289
1290
1290
    /** {@inheritDoc} */
1291
    /** {@inheritDoc} */
1292
    public KeepProperty getKeepWithPreviousProperty() {
1293
        return ((BlockLevelLayoutManager) getParent()).getKeepWithPreviousProperty();
1294
    }
1295
1296
    /** {@inheritDoc} */
1297
    public KeepProperty getKeepWithNextProperty() {
1298
        return ((BlockLevelLayoutManager) getParent()).getKeepWithNextProperty();
1299
    }
1300
1301
    /** {@inheritDoc} */
1302
    public Keep getKeepTogether() {
1303
        return ((BlockLevelLayoutManager) getParent()).getKeepTogether();
1304
    }
1305
1306
    /** {@inheritDoc} */
1291
    public boolean mustKeepWithPrevious() {
1307
    public boolean mustKeepWithPrevious() {
1292
        return getKeepWithPreviousStrength() > KEEP_AUTO;
1308
        return !getKeepWithPrevious().isAuto();
1293
    }
1309
    }
1294
1310
1295
    /** {@inheritDoc} */
1311
    /** {@inheritDoc} */
1296
    public boolean mustKeepWithNext() {
1312
    public boolean mustKeepWithNext() {
1297
        return getKeepWithNextStrength() > KEEP_AUTO;
1313
        return !getKeepWithNext().isAuto();
1298
    }
1314
    }
1299
1315
1300
    /** {@inheritDoc} */
1316
    /** {@inheritDoc} */
1301
    public int getKeepWithNextStrength() {
1317
    public Keep getKeepWithNext() {
1302
        return KEEP_AUTO;
1318
        return Keep.KEEP_AUTO;
1303
    }
1319
    }
1304
1320
1305
    /** {@inheritDoc} */
1321
    /** {@inheritDoc} */
1306
    public int getKeepWithPreviousStrength() {
1322
    public Keep getKeepWithPrevious() {
1307
        return KEEP_AUTO;
1323
        return Keep.KEEP_AUTO;
1308
    }
1324
    }
1309
1325
1310
    /** {@inheritDoc} */
1326
    /** {@inheritDoc} */
(-)src/java/org/apache/fop/layoutmgr/AbstractBreaker.java (-2 / +8 lines)
Lines 399-405 Link Here
399
                ListElement lastBreakElement = effectiveList.getElement(endElementIndex);
399
                ListElement lastBreakElement = effectiveList.getElement(endElementIndex);
400
                if (lastBreakElement.isPenalty()) {
400
                if (lastBreakElement.isPenalty()) {
401
                    KnuthPenalty pen = (KnuthPenalty)lastBreakElement;
401
                    KnuthPenalty pen = (KnuthPenalty)lastBreakElement;
402
                    lastBreakClass = pen.getBreakClass();
402
                    // TODO Handle keep.within-column differently so that break class is
403
                    // automatically set to the right value
404
                    if (pen.getP() >= KnuthPenalty.INFINITE - 1) {
405
                        lastBreakClass = Constants.EN_COLUMN;
406
                    } else {
407
                        lastBreakClass = pen.getBreakClass();
408
                    }
403
                } else {
409
                } else {
404
                    lastBreakClass = Constants.EN_COLUMN;
410
                    lastBreakClass = Constants.EN_COLUMN;
405
                }
411
                }
Lines 562-568 Link Here
562
            nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn);
568
            nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn);
563
569
564
            Position breakPosition = null;
570
            Position breakPosition = null;
565
            if (((KnuthElement) ListUtil.getLast(returnedList)).isForcedBreak()) {
571
            if (ElementListUtils.endsWithForcedBreak(returnedList)) {
566
                KnuthPenalty breakPenalty = (KnuthPenalty) ListUtil
572
                KnuthPenalty breakPenalty = (KnuthPenalty) ListUtil
567
                        .removeLast(returnedList);
573
                        .removeLast(returnedList);
568
                breakPosition = breakPenalty.getPosition();
574
                breakPosition = breakPenalty.getPosition();
(-)src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java (-8 / +31 lines)
Lines 19-24 Link Here
19
19
20
package org.apache.fop.layoutmgr;
20
package org.apache.fop.layoutmgr;
21
21
22
import org.apache.fop.fo.properties.KeepProperty;
23
22
/**
24
/**
23
 * The interface for LayoutManagers which generate block areas
25
 * The interface for LayoutManagers which generate block areas
24
 */
26
 */
Lines 35-45 Link Here
35
    /** Adjustment class: adjustment for line height */
37
    /** Adjustment class: adjustment for line height */
36
    int LINE_HEIGHT_ADJUSTMENT = 3;
38
    int LINE_HEIGHT_ADJUSTMENT = 3;
37
39
38
    /** The integer value for "auto" keep strength */
39
    int KEEP_AUTO = Integer.MIN_VALUE;
40
    /** The integer value for "always" keep strength */
41
    int KEEP_ALWAYS = Integer.MAX_VALUE;
42
43
    int negotiateBPDAdjustment(int adj, KnuthElement lastElement);
40
    int negotiateBPDAdjustment(int adj, KnuthElement lastElement);
44
41
45
    void discardSpace(KnuthGlue spaceGlue);
42
    void discardSpace(KnuthGlue spaceGlue);
Lines 48-54 Link Here
48
     * Returns the keep-together strength for this element.
45
     * Returns the keep-together strength for this element.
49
     * @return the keep-together strength
46
     * @return the keep-together strength
50
     */
47
     */
51
    int getKeepTogetherStrength();
48
    Keep getKeepTogether();
52
49
53
    /**
50
    /**
54
     * @return true if this element must be kept together
51
     * @return true if this element must be kept together
Lines 59-65 Link Here
59
     * Returns the keep-with-previous strength for this element.
56
     * Returns the keep-with-previous strength for this element.
60
     * @return the keep-with-previous strength
57
     * @return the keep-with-previous strength
61
     */
58
     */
62
    int getKeepWithPreviousStrength();
59
    Keep getKeepWithPrevious();
63
60
64
    /**
61
    /**
65
     * @return true if this element must be kept with the previous element.
62
     * @return true if this element must be kept with the previous element.
Lines 70-80 Link Here
70
     * Returns the keep-with-next strength for this element.
67
     * Returns the keep-with-next strength for this element.
71
     * @return the keep-with-next strength
68
     * @return the keep-with-next strength
72
     */
69
     */
73
    int getKeepWithNextStrength();
70
    Keep getKeepWithNext();
74
71
75
    /**
72
    /**
76
     * @return true if this element must be kept with the next element.
73
     * @return true if this element must be kept with the next element.
77
     */
74
     */
78
    boolean mustKeepWithNext();
75
    boolean mustKeepWithNext();
79
76
77
    /**
78
     * Returns the keep-together property specified on the FObj.
79
     * (optional operation)
80
     * @return the keep-together property
81
     * @throws UnsupportedOperationException if the method is not
82
     *         supported by this LM
83
     */
84
    KeepProperty getKeepTogetherProperty();
85
86
    /**
87
     * Returns the keep-with-previous property specified on the FObj.
88
     * (optional operation)
89
     * @return the keep-together property
90
     * @throws UnsupportedOperationException if the method is not
91
     *         supported by this LM
92
     */
93
    KeepProperty getKeepWithPreviousProperty();
94
95
    /**
96
     * Returns the keep-with-next property specified on the FObj.
97
     * (optional operation)
98
     * @return the keep-together property
99
     * @throws UnsupportedOperationException if the method is not
100
     *         supported by this LM
101
     */
102
    KeepProperty getKeepWithNextProperty();
80
}
103
}
(-)src/java/org/apache/fop/layoutmgr/LayoutContext.java (-17 / +16 lines)
Lines 145-152 Link Here
145
    private int breakBefore;
145
    private int breakBefore;
146
    private int breakAfter;
146
    private int breakAfter;
147
147
148
    private int pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
148
    private Keep pendingKeepWithNext = Keep.KEEP_AUTO;
149
    private int pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
149
    private Keep pendingKeepWithPrevious = Keep.KEEP_AUTO;
150
150
151
    private int disableColumnBalancing;
151
    private int disableColumnBalancing;
152
152
Lines 237-243 Link Here
237
     * Returns the strength of a keep-with-next currently pending.
237
     * Returns the strength of a keep-with-next currently pending.
238
     * @return the keep-with-next strength
238
     * @return the keep-with-next strength
239
     */
239
     */
240
    public int getKeepWithNextPending() {
240
    public Keep getKeepWithNextPending() {
241
        return this.pendingKeepWithNext;
241
        return this.pendingKeepWithNext;
242
    }
242
    }
243
243
Lines 245-251 Link Here
245
     * Returns the strength of a keep-with-previous currently pending.
245
     * Returns the strength of a keep-with-previous currently pending.
246
     * @return the keep-with-previous strength
246
     * @return the keep-with-previous strength
247
     */
247
     */
248
    public int getKeepWithPreviousPending() {
248
    public Keep getKeepWithPreviousPending() {
249
        return this.pendingKeepWithPrevious;
249
        return this.pendingKeepWithPrevious;
250
    }
250
    }
251
251
Lines 253-266 Link Here
253
     * Clears any pending keep-with-next strength.
253
     * Clears any pending keep-with-next strength.
254
     */
254
     */
255
    public void clearKeepWithNextPending() {
255
    public void clearKeepWithNextPending() {
256
        this.pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
256
        this.pendingKeepWithNext = Keep.KEEP_AUTO;
257
    }
257
    }
258
258
259
    /**
259
    /**
260
     * Clears any pending keep-with-previous strength.
260
     * Clears any pending keep-with-previous strength.
261
     */
261
     */
262
    public void clearKeepWithPreviousPending() {
262
    public void clearKeepWithPreviousPending() {
263
        this.pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
263
        this.pendingKeepWithPrevious = Keep.KEEP_AUTO;
264
    }
264
    }
265
265
266
    /**
266
    /**
Lines 273-290 Link Here
273
273
274
    /**
274
    /**
275
     * Updates the currently pending keep-with-next strength.
275
     * Updates the currently pending keep-with-next strength.
276
     * @param strength the new strength to consider
276
     * @param keep the new strength to consider
277
     */
277
     */
278
    public void updateKeepWithNextPending(int strength) {
278
    public void updateKeepWithNextPending(Keep keep) {
279
        this.pendingKeepWithNext = Math.max(this.pendingKeepWithNext, strength);
279
        this.pendingKeepWithNext = this.pendingKeepWithNext.compare(keep);
280
    }
280
    }
281
281
282
    /**
282
    /**
283
     * Updates the currently pending keep-with-previous strength.
283
     * Updates the currently pending keep-with-previous strength.
284
     * @param strength the new strength to consider
284
     * @param keep the new strength to consider
285
     */
285
     */
286
    public void updateKeepWithPreviousPending(int strength) {
286
    public void updateKeepWithPreviousPending(Keep keep) {
287
        this.pendingKeepWithPrevious = Math.max(this.pendingKeepWithPrevious, strength);
287
        this.pendingKeepWithPrevious = this.pendingKeepWithPrevious.compare(keep);
288
    }
288
    }
289
289
290
    /**
290
    /**
Lines 292-298 Link Here
292
     * @return true if a keep-with-next constraint is pending
292
     * @return true if a keep-with-next constraint is pending
293
     */
293
     */
294
    public boolean isKeepWithNextPending() {
294
    public boolean isKeepWithNextPending() {
295
        return getKeepWithNextPending() != BlockLevelLayoutManager.KEEP_AUTO;
295
        return !getKeepWithNextPending().isAuto();
296
    }
296
    }
297
297
298
    /**
298
    /**
Lines 300-306 Link Here
300
     * @return true if a keep-with-previous constraint is pending
300
     * @return true if a keep-with-previous constraint is pending
301
     */
301
     */
302
    public boolean isKeepWithPreviousPending() {
302
    public boolean isKeepWithPreviousPending() {
303
        return getKeepWithPreviousPending() != BlockLevelLayoutManager.KEEP_AUTO;
303
        return !getKeepWithPreviousPending().isAuto();
304
    }
304
    }
305
305
306
    public void setLeadingSpace(SpaceSpecifier space) {
306
    public void setLeadingSpace(SpaceSpecifier space) {
Lines 677-685 Link Here
677
        + "\nStarts New Area: \t" + startsNewArea()
677
        + "\nStarts New Area: \t" + startsNewArea()
678
        + "\nIs Last Area: \t" + isLastArea()
678
        + "\nIs Last Area: \t" + isLastArea()
679
        + "\nTry Hyphenate: \t" + tryHyphenate()
679
        + "\nTry Hyphenate: \t" + tryHyphenate()
680
        + "\nKeeps: \t[keep-with-next=" + KeepUtil.keepStrengthToString(getKeepWithNextPending())
680
        + "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending()
681
                + "][keep-with-previous="
681
                + "][keep-with-previous=" + getKeepWithPreviousPending() + "] pending"
682
                + KeepUtil.keepStrengthToString(getKeepWithPreviousPending()) + "] pending"
683
        + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
682
        + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
684
        + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
683
        + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
685
    }
684
    }
(-)src/java/org/apache/fop/layoutmgr/Keep.java (+156 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work for additional information
4
 * regarding copyright ownership. The ASF licenses this file to You under the Apache
5
 * License, Version 2.0 (the "License"); you may not use this file except in compliance
6
 * with the License. You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software distributed under
11
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
12
 * KIND, either express or implied. See the License for the specific language governing
13
 * permissions and limitations under the License.
14
 */
15
16
/* $Id$ */
17
18
package org.apache.fop.layoutmgr;
19
20
import org.apache.fop.fo.Constants;
21
import org.apache.fop.fo.properties.KeepProperty;
22
import org.apache.fop.fo.properties.Property;
23
24
/**
25
 * Object representing a keep constraint, corresponding
26
 * to the XSL-FO <a href="http://www.w3.org/TR/xsl/#d0e26492">keep properties</a>.
27
 */
28
public class Keep {
29
30
    /** The integer value for "auto" keep strength. */
31
    private static final int STRENGTH_AUTO = Integer.MIN_VALUE;
32
33
    /** The integer value for "always" keep strength. */
34
    private static final int STRENGTH_ALWAYS = Integer.MAX_VALUE;
35
36
    public static final Keep KEEP_AUTO = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);
37
38
    public static final Keep KEEP_ALWAYS = new Keep(STRENGTH_ALWAYS, Constants.EN_LINE);
39
40
    private int strength = STRENGTH_AUTO;
41
42
    private int context;
43
44
    private Keep(int strength, int context) {
45
        this.strength = strength;
46
        this.context = context;
47
    }
48
49
    private static int getKeepStrength(Property keep) {
50
        if (keep.isAuto()) {
51
            return STRENGTH_AUTO;
52
        } else if (keep.getEnum() == Constants.EN_ALWAYS) {
53
            return STRENGTH_ALWAYS;
54
        } else {
55
            return keep.getNumber().intValue();
56
        }
57
    }
58
59
    /**
60
     * Obtain a Keep instance corresponding to the given {@link KeepProperty}
61
     *
62
     * @param keepProperty  the {@link KeepProperty}
63
     * @return  a new instance corresponding to the given property
64
     */
65
    public static Keep getKeep(KeepProperty keepProperty) {
66
        Keep keep = new Keep(STRENGTH_AUTO, Constants.EN_AUTO);
67
        keep.update(keepProperty.getWithinPage(),   Constants.EN_PAGE);
68
        keep.update(keepProperty.getWithinColumn(), Constants.EN_COLUMN);
69
        keep.update(keepProperty.getWithinLine(),   Constants.EN_LINE);
70
        return keep;
71
    }
72
73
    private void update(Property keep, int context) {
74
        if (!keep.isAuto()) {
75
            this.strength = getKeepStrength(keep);
76
            this.context = context;
77
        }
78
    }
79
80
    /** @return {@code true} if the keep property was specified as "auto" */
81
    public boolean isAuto() {
82
        return (this.strength == STRENGTH_AUTO);
83
    }
84
85
    /**
86
     * Returns the context of this keep.
87
     *
88
     * @return one of {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or
89
     * {@link Constants#EN_PAGE}
90
     */
91
    public int getContext() {
92
        return this.context;
93
    }
94
95
    /**
96
     * Return the penalty value corresponding to the strength of this Keep.
97
     * <em>Note: integer keep-values will all result in the same penalty value.</em>
98
     * @return the penalty value corresponding to the strength of this Keep */
99
    public int getPenalty() {
100
        if (strength == STRENGTH_AUTO) {
101
            return 0;
102
        } else if (strength == STRENGTH_ALWAYS) {
103
            return KnuthElement.INFINITE;
104
        } else {
105
            return KnuthElement.INFINITE - 1;
106
        }
107
    }
108
109
    private static int getKeepContextPriority(int context) {
110
        switch (context) {
111
        case Constants.EN_LINE:   return 0;
112
        case Constants.EN_COLUMN: return 1;
113
        case Constants.EN_PAGE:   return 2;
114
        case Constants.EN_AUTO:   return 3;
115
        default: throw new IllegalArgumentException();
116
        }
117
    }
118
119
    /**
120
     * Compare this Keep instance to another one, and return the
121
     * stronger one if the context is the same
122
     *
123
     * @param other     the instance to compare to
124
     * @return  the winning Keep instance
125
     */
126
    public Keep compare(Keep other) {
127
128
        /* check strength "always" first, regardless of priority */
129
        if (this.strength == STRENGTH_ALWAYS
130
                && this.strength > other.strength) {
131
            return this;
132
        } else if (other.strength == STRENGTH_ALWAYS
133
                && other.strength > this.strength) {
134
            return other;
135
        }
136
137
        int pThis = getKeepContextPriority(this.context);
138
        int pOther = getKeepContextPriority(other.context);
139
140
        /* equal priority: strongest wins */
141
        if (pThis == pOther) {
142
            return (strength >= other.strength) ? this : other;
143
        }
144
145
        /* different priority: lowest priority wins */
146
        return (pThis < pOther) ? this : other;
147
    }
148
149
    /** {@inheritDoc} */
150
    public String toString() {
151
        return (strength == STRENGTH_AUTO) ? "auto"
152
                : (strength == STRENGTH_ALWAYS) ? "always"
153
                        : Integer.toString(strength);
154
    }
155
156
}
0
  + Id
157
  + Id
1
  + native
158
  + native
(-)src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (-15 / +10 lines)
Lines 37-42 Link Here
37
import org.apache.fop.datatypes.Length;
37
import org.apache.fop.datatypes.Length;
38
import org.apache.fop.fo.flow.BlockContainer;
38
import org.apache.fop.fo.flow.BlockContainer;
39
import org.apache.fop.fo.properties.CommonAbsolutePosition;
39
import org.apache.fop.fo.properties.CommonAbsolutePosition;
40
import org.apache.fop.fo.properties.KeepProperty;
40
import org.apache.fop.traits.MinOptMax;
41
import org.apache.fop.traits.MinOptMax;
41
import org.apache.fop.traits.SpaceVal;
42
import org.apache.fop.traits.SpaceVal;
42
import org.apache.fop.util.ListUtil;
43
import org.apache.fop.util.ListUtil;
Lines 261-267 Link Here
261
262
262
        if (!firstVisibleMarkServed) {
263
        if (!firstVisibleMarkServed) {
263
            addKnuthElementsForSpaceBefore(returnList, alignment);
264
            addKnuthElementsForSpaceBefore(returnList, alignment);
264
            context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
265
            context.updateKeepWithPreviousPending(getKeepWithPrevious());
265
        }
266
        }
266
267
267
        addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
268
        addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
Lines 323-330 Link Here
323
                        //Avoid NoSuchElementException below (happens with empty blocks)
324
                        //Avoid NoSuchElementException below (happens with empty blocks)
324
                        continue;
325
                        continue;
325
                    }
326
                    }
326
                    if (((ListElement) ListUtil.getLast(returnedList))
327
                    if (ElementListUtils.endsWithForcedBreak(returnedList)) {
327
                            .isForcedBreak()) {
328
                        // a descendant of this block has break-after
328
                        // a descendant of this block has break-after
329
                        if (curLM.isFinished()) {
329
                        if (curLM.isFinished()) {
330
                            // there is no other content in this block;
330
                            // there is no other content in this block;
Lines 391-397 Link Here
391
        context.clearPendingMarks();
391
        context.clearPendingMarks();
392
        addKnuthElementsForBreakAfter(returnList, context);
392
        addKnuthElementsForBreakAfter(returnList, context);
393
393
394
        context.updateKeepWithNextPending(getKeepWithNextStrength());
394
        context.updateKeepWithNextPending(getKeepWithNext());
395
395
396
        setFinished(true);
396
        setFinished(true);
397
        return returnList;
397
        return returnList;
Lines 1011-1033 Link Here
1011
    }
1011
    }
1012
1012
1013
    /** {@inheritDoc} */
1013
    /** {@inheritDoc} */
1014
    public int getKeepTogetherStrength() {
1014
    public KeepProperty getKeepTogetherProperty() {
1015
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
1015
        return getBlockContainerFO().getKeepTogether();
1016
                getBlockContainerFO().getKeepTogether());
1017
        strength = Math.max(strength, getParentKeepTogetherStrength());
1018
        return strength;
1019
    }
1016
    }
1020
1017
1021
    /** {@inheritDoc} */
1018
    /** {@inheritDoc} */
1022
    public int getKeepWithNextStrength() {
1019
    public KeepProperty getKeepWithPreviousProperty() {
1023
        return KeepUtil.getCombinedBlockLevelKeepStrength(
1020
        return getBlockContainerFO().getKeepWithPrevious();
1024
                getBlockContainerFO().getKeepWithNext());
1025
    }
1021
    }
1026
1022
1027
    /** {@inheritDoc} */
1023
    /** {@inheritDoc} */
1028
    public int getKeepWithPreviousStrength() {
1024
    public KeepProperty getKeepWithNextProperty() {
1029
        return KeepUtil.getCombinedBlockLevelKeepStrength(
1025
        return getBlockContainerFO().getKeepWithNext();
1030
                getBlockContainerFO().getKeepWithPrevious());
1031
    }
1026
    }
1032
1027
1033
    /**
1028
    /**
(-)src/java/org/apache/fop/layoutmgr/BreakElement.java (-1 / +16 lines)
Lines 41-49 Link Here
41
     * @param context the layout context which contains the pending conditional elements
41
     * @param context the layout context which contains the pending conditional elements
42
     */
42
     */
43
    public BreakElement(Position position, int penaltyValue, LayoutContext context) {
43
    public BreakElement(Position position, int penaltyValue, LayoutContext context) {
44
        this(position, 0, penaltyValue, -1, context);
44
        this(position, penaltyValue, -1, context);
45
    }
45
    }
46
46
47
    public BreakElement(Position position, int penaltyValue, int breakClass, LayoutContext context) {
48
        this(position, 0, penaltyValue, breakClass, context);
49
    }
50
47
    /**
51
    /**
48
     * Constructor for hard breaks.
52
     * Constructor for hard breaks.
49
     *
53
     *
Lines 168-173 Link Here
168
        sb.append("; w:");
172
        sb.append("; w:");
169
        sb.append(penaltyWidth);
173
        sb.append(penaltyWidth);
170
        sb.append("]");
174
        sb.append("]");
175
        switch (getBreakClass()) {
176
        case Constants.EN_PAGE:
177
            sb.append(" (page context)");
178
            break;
179
        case Constants.EN_COLUMN:
180
            sb.append(" (column context)");
181
            break;
182
        case Constants.EN_LINE:
183
            sb.append(" (line context)");
184
            break;
185
        }
171
        return sb.toString();
186
        return sb.toString();
172
    }
187
    }
173
188
(-)src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java (-15 / +10 lines)
Lines 63-72 Link Here
63
    /** {@inheritDoc} */
63
    /** {@inheritDoc} */
64
    public List getNextKnuthElements(LayoutContext context, int alignment) {
64
    public List getNextKnuthElements(LayoutContext context, int alignment) {
65
65
66
        // set layout dimensions
67
        int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
68
        int flowBPD = getCurrentPV().getBodyRegion().getBPD();
69
70
        // currently active LM
66
        // currently active LM
71
        LayoutManager curLM;
67
        LayoutManager curLM;
72
        List returnedList;
68
        List returnedList;
Lines 84-95 Link Here
84
            int disableColumnBalancing = EN_FALSE;
80
            int disableColumnBalancing = EN_FALSE;
85
            if (curLM instanceof BlockLayoutManager) {
81
            if (curLM instanceof BlockLayoutManager) {
86
                span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
82
                span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
87
                disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO()
83
                disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO().getDisableColumnBalancing();
88
                        .getDisableColumnBalancing();
89
            } else if (curLM instanceof BlockContainerLayoutManager) {
84
            } else if (curLM instanceof BlockContainerLayoutManager) {
90
                span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
85
                span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
91
                disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO()
86
                disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO().getDisableColumnBalancing();
92
                        .getDisableColumnBalancing();
93
            }
87
            }
94
88
95
            int currentSpan = context.getCurrentSpan();
89
            int currentSpan = context.getCurrentSpan();
Lines 113-118 Link Here
113
107
114
            // get elements from curLM
108
            // get elements from curLM
115
            returnedList = curLM.getNextKnuthElements(childLC, alignment);
109
            returnedList = curLM.getNextKnuthElements(childLC, alignment);
110
            //int contentHeight = ElementListUtils.calcContentLength(returnedList);
116
            //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
111
            //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
117
            if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
112
            if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
118
                context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
113
                context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
Lines 154-160 Link Here
154
            context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
149
            context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
155
            childLC.clearKeepWithNextPending();
150
            childLC.clearKeepWithNextPending();
156
151
157
            context.updateKeepWithNextPending(getKeepWithNextStrength());
152
            context.updateKeepWithNextPending(getKeepWithNext());
158
        }
153
        }
159
154
160
        SpaceResolver.resolveElementList(returnList);
155
        SpaceResolver.resolveElementList(returnList);
Lines 203-220 Link Here
203
    }
198
    }
204
199
205
    /** {@inheritDoc} */
200
    /** {@inheritDoc} */
206
    public int getKeepTogetherStrength() {
201
    public Keep getKeepTogether() {
207
        return KEEP_AUTO;
202
        return Keep.KEEP_AUTO;
208
    }
203
    }
209
204
210
    /** {@inheritDoc} */
205
    /** {@inheritDoc} */
211
    public int getKeepWithNextStrength() {
206
    public Keep getKeepWithNext() {
212
        return KEEP_AUTO;
207
        return Keep.KEEP_AUTO;
213
    }
208
    }
214
209
215
    /** {@inheritDoc} */
210
    /** {@inheritDoc} */
216
    public int getKeepWithPreviousStrength() {
211
    public Keep getKeepWithPrevious() {
217
        return KEEP_AUTO;
212
        return Keep.KEEP_AUTO;
218
    }
213
    }
219
214
220
    /** {@inheritDoc} */
215
    /** {@inheritDoc} */
(-)src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java (-6 / +6 lines)
Lines 92-109 Link Here
92
    }
92
    }
93
93
94
    /** {@inheritDoc} */
94
    /** {@inheritDoc} */
95
    public int getKeepTogetherStrength() {
95
    public Keep getKeepTogether() {
96
        return getParentKeepTogetherStrength();
96
        return getParentKeepTogether();
97
    }
97
    }
98
98
99
    /** {@inheritDoc} */
99
    /** {@inheritDoc} */
100
    public int getKeepWithNextStrength() {
100
    public Keep getKeepWithNext() {
101
        return KEEP_AUTO;
101
        return Keep.KEEP_AUTO;
102
    }
102
    }
103
103
104
    /** {@inheritDoc} */
104
    /** {@inheritDoc} */
105
    public int getKeepWithPreviousStrength() {
105
    public Keep getKeepWithPrevious() {
106
        return KEEP_AUTO;
106
        return Keep.KEEP_AUTO;
107
    }
107
    }
108
108
109
}
109
}
(-)src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (-9 / +6 lines)
Lines 210-230 Link Here
210
    }
210
    }
211
211
212
    /** {@inheritDoc} */
212
    /** {@inheritDoc} */
213
    public int getKeepTogetherStrength() {
213
    public KeepProperty getKeepTogetherProperty() {
214
        KeepProperty keep = getBlockFO().getKeepTogether();
214
        return getBlockFO().getKeepTogether();
215
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(keep);
216
        strength = Math.max(strength, getParentKeepTogetherStrength());
217
        return strength;
218
    }
215
    }
219
216
220
    /** {@inheritDoc} */
217
    /** {@inheritDoc} */
221
    public int getKeepWithNextStrength() {
218
    public KeepProperty getKeepWithPreviousProperty() {
222
        return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithNext());
219
        return getBlockFO().getKeepWithPrevious();
223
    }
220
    }
224
221
225
    /** {@inheritDoc} */
222
    /** {@inheritDoc} */
226
    public int getKeepWithPreviousStrength() {
223
    public KeepProperty getKeepWithNextProperty() {
227
        return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithPrevious());
224
        return getBlockFO().getKeepWithNext();
228
    }
225
    }
229
226
230
    /** {@inheritDoc} */
227
    /** {@inheritDoc} */
(-)src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java (-49 / +222 lines)
Lines 20-37 Link Here
20
package org.apache.fop.layoutmgr;
20
package org.apache.fop.layoutmgr;
21
21
22
import java.util.ArrayList;
22
import java.util.ArrayList;
23
import java.util.Iterator;
23
import java.util.LinkedList;
24
import java.util.LinkedList;
24
import java.util.List;
25
import java.util.List;
25
import java.util.ListIterator;
26
import java.util.ListIterator;
26
27
27
import org.apache.commons.logging.Log;
28
import org.apache.commons.logging.Log;
28
import org.apache.commons.logging.LogFactory;
29
import org.apache.commons.logging.LogFactory;
30
29
import org.apache.fop.fo.Constants;
31
import org.apache.fop.fo.Constants;
30
import org.apache.fop.fo.FObj;
32
import org.apache.fop.fo.FObj;
31
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
33
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
32
import org.apache.fop.traits.MinOptMax;
34
import org.apache.fop.traits.MinOptMax;
35
import org.apache.fop.util.ListUtil;
33
36
34
class PageBreakingAlgorithm extends BreakingAlgorithm {
37
public class PageBreakingAlgorithm extends BreakingAlgorithm {
35
38
36
    /** the logger for the class */
39
    /** the logger for the class */
37
    private static Log log = LogFactory.getLog(PageBreakingAlgorithm.class);
40
    private static Log log = LogFactory.getLog(PageBreakingAlgorithm.class);
Lines 47-55 Link Here
47
     * List&lt;List&lt;KnuthElement&gt;&gt;, it contains the sequences of KnuthElement
50
     * List&lt;List&lt;KnuthElement&gt;&gt;, it contains the sequences of KnuthElement
48
     * representing the footnotes bodies.
51
     * representing the footnotes bodies.
49
     */
52
     */
50
    private ArrayList footnotesList = null;
53
    private List footnotesList = null;
51
    /** Cumulated bpd of unhandled footnotes. */
54
    /** Cumulated bpd of unhandled footnotes. */
52
    private ArrayList lengthList = null;
55
    private List lengthList = null;
53
    /** Length of all the footnotes which will be put on the current page. */
56
    /** Length of all the footnotes which will be put on the current page. */
54
    private int totalFootnotesLength = 0;
57
    private int totalFootnotesLength = 0;
55
    /**
58
    /**
Lines 58-63 Link Here
58
     * footnotes from its preceding pages.
61
     * footnotes from its preceding pages.
59
     */
62
     */
60
    private int insertedFootnotesLength = 0;
63
    private int insertedFootnotesLength = 0;
64
61
    /** True if footnote citations have been met since the beginning of the page sequence. */
65
    /** True if footnote citations have been met since the beginning of the page sequence. */
62
    private boolean footnotesPending = false;
66
    private boolean footnotesPending = false;
63
    /**
67
    /**
Lines 178-183 Link Here
178
        }
182
        }
179
    }
183
    }
180
184
185
    /** {@inheritDoc} */
181
    protected void initialize() {
186
    protected void initialize() {
182
        super.initialize();
187
        super.initialize();
183
        insertedFootnotesLength = 0;
188
        insertedFootnotesLength = 0;
Lines 185-190 Link Here
185
        footnoteElementIndex = -1;
190
        footnoteElementIndex = -1;
186
    }
191
    }
187
192
193
    private int currentKeepContext = Constants.EN_AUTO;
194
    private KnuthNode lastBeforeKeepContextSwitch;
195
196
    /**
197
     * {@inheritDoc}
198
     * Overridden to defer a part to the next page, if it
199
     * must be kept within one page, but is too large to fit in
200
     * the last N-1 columns.
201
     */
202
    protected KnuthNode recoverFromTooLong(KnuthNode lastTooLong) {
203
204
        // return super.recoverFromTooLong(lastTooLong);
205
        if (log.isDebugEnabled()) {
206
            log.debug("Recovering from too long: " + lastTooLong);
207
        }
208
209
        if (lastBeforeKeepContextSwitch == null
210
                || currentKeepContext == Constants.EN_AUTO) {
211
            return super.recoverFromTooLong(lastTooLong);
212
        }
213
214
        KnuthNode node = lastBeforeKeepContextSwitch;
215
        lastBeforeKeepContextSwitch = null;
216
        // content would overflow, insert empty page/column(s) and try again
217
        while (!pageProvider.endPage(node.line + 1)) {
218
            node = createNode(
219
                    node.position,
220
                    node.line + 1, 1,
221
                    0, 0, 0,
222
                    0, 0, 0,
223
                    0, 0, node);
224
        }
225
        return node;
226
    }
227
228
    /**
229
     * {@inheritDoc}
230
     * Overridden to return the last page-break node, instead of the node with the highest
231
     * position index (which may actually be a column-break node)
232
     */
233
    protected KnuthNode compareNodes(KnuthNode node1, KnuthNode node2) {
234
235
        //if either node is null, return the other one
236
        if (node1 == null || node2 == null) {
237
            return (node2 == null) ? node1 : node2;
238
        }
239
240
        //if the PageProvider has been properly initialized,
241
        //check whether either one of the nodes does not start a page
242
        //while the other one does
243
        //if so, return the one that corresponds to a page-break
244
        if (pageProvider != null) {
245
            if (!pageProvider.endPage(node1.line)
246
                    && pageProvider.endPage(node2.line)) {
247
                return node2;
248
            } else if (!pageProvider.endPage(node2.line)
249
                    && pageProvider.endPage(node1.line)) {
250
                return node1;
251
            }
252
        }
253
254
        //all other cases: use superclass implementation
255
        return super.compareNodes(node1, node2);
256
    }
257
258
    /** {@inheritDoc} */
188
    protected KnuthNode createNode(int position, int line, int fitness,
259
    protected KnuthNode createNode(int position, int line, int fitness,
189
                                   int totalWidth, int totalStretch, int totalShrink,
260
                                   int totalWidth, int totalStretch, int totalShrink,
190
                                   double adjustRatio, int availableShrink, int availableStretch,
261
                                   double adjustRatio, int availableShrink, int availableStretch,
Lines 196-201 Link Here
196
                                 difference, totalDemerits, previous);
267
                                 difference, totalDemerits, previous);
197
    }
268
    }
198
269
270
    /** {@inheritDoc} */
199
    protected KnuthNode createNode(int position, int line, int fitness,
271
    protected KnuthNode createNode(int position, int line, int fitness,
200
                                   int totalWidth, int totalStretch, int totalShrink) {
272
                                   int totalWidth, int totalStretch, int totalShrink) {
201
        return new KnuthPageNode(position, line, fitness,
273
        return new KnuthPageNode(position, line, fitness,
Lines 209-214 Link Here
209
    }
281
    }
210
282
211
    /**
283
    /**
284
     * {@inheritDoc}
212
     * Page-breaking specific handling of the given box. Currently it adds the footnotes
285
     * Page-breaking specific handling of the given box. Currently it adds the footnotes
213
     * cited in the given box to the list of to-be-handled footnotes.
286
     * cited in the given box to the list of to-be-handled footnotes.
214
     * @param box a block-level element possibly containing foonotes citations
287
     * @param box a block-level element possibly containing foonotes citations
Lines 222-230 Link Here
222
                firstNewFootnoteIndex = footnotesList.size() - 1;
295
                firstNewFootnoteIndex = footnotesList.size() - 1;
223
            }
296
            }
224
        }
297
        }
298
        super.handleBox(box);
225
    }
299
    }
226
300
227
    /**
301
    /**
302
     * {@inheritDoc}
303
     * Overridden to consider penalties with value {@link KnuthElement#INFINITE}
304
     * as legal break-points, if the current keep-context allows this
305
     * (a keep-*.within-page="always" constraint still permits column-breaks)
306
     */
307
    protected void handlePenaltyAt(KnuthPenalty penalty, int position,
308
                                   int allowedBreaks) {
309
        super.handlePenaltyAt(penalty, position, allowedBreaks);
310
        /* if the penalty had value INFINITE, default implementation
311
         * will not have considered it a legal break, do so now
312
         */
313
        if (penalty.getP() == KnuthPenalty.INFINITE) {
314
            int breakClass = penalty.getBreakClass();
315
            if (breakClass == Constants.EN_PAGE
316
                    || breakClass == Constants.EN_COLUMN) {
317
                considerLegalBreak(penalty, position);
318
            }
319
        }
320
    }
321
322
    /**
228
     * Handles the footnotes cited inside a block-level box. Updates footnotesList and the
323
     * Handles the footnotes cited inside a block-level box. Updates footnotesList and the
229
     * value of totalFootnotesLength with the lengths of the given footnotes.
324
     * value of totalFootnotesLength with the lengths of the given footnotes.
230
     * @param elementLists list of KnuthElement sequences corresponding to the footnotes
325
     * @param elementLists list of KnuthElement sequences corresponding to the footnotes
Lines 244-252 Link Here
244
        }
339
        }
245
340
246
        // compute the total length of the footnotes
341
        // compute the total length of the footnotes
247
        ListIterator elementListsIterator = elementLists.listIterator();
342
        for (Iterator elementListsIterator = elementLists.iterator();
248
        while (elementListsIterator.hasNext()) {
343
                elementListsIterator.hasNext();) {
249
            LinkedList noteList = (LinkedList) elementListsIterator.next();
344
            final List noteList = (List) elementListsIterator.next();
250
345
251
            //Space resolution (Note: this does not respect possible stacking constraints
346
            //Space resolution (Note: this does not respect possible stacking constraints
252
            //between footnotes!)
347
            //between footnotes!)
Lines 254-274 Link Here
254
349
255
            int noteLength = 0;
350
            int noteLength = 0;
256
            footnotesList.add(noteList);
351
            footnotesList.add(noteList);
257
            ListIterator noteListIterator = noteList.listIterator();
352
            for (Iterator noteListIterator = noteList.iterator();
258
            while (noteListIterator.hasNext()) {
353
                    noteListIterator.hasNext();) {
259
                KnuthElement element = (KnuthElement) noteListIterator.next();
354
                final KnuthElement element = (KnuthElement) noteListIterator.next();
260
                if (element.isBox() || element.isGlue()) {
355
                if (element.isBox() || element.isGlue()) {
261
                    noteLength += element.getW();
356
                    noteLength += element.getW();
262
                }
357
                }
263
            }
358
            }
264
            int prevLength = (lengthList.size() == 0
359
            int prevLength = (lengthList == null || lengthList.isEmpty())
265
                    ? 0
360
                    ? 0
266
                    : ((Integer) lengthList.get(lengthList.size() - 1)).intValue());
361
                    : ((Integer) ListUtil.getLast(lengthList)).intValue();
362
            //TODO: replace with Integer.valueOf() once we switch to Java 5
267
            lengthList.add(new Integer(prevLength + noteLength));
363
            lengthList.add(new Integer(prevLength + noteLength));
268
            totalFootnotesLength += noteLength;
364
            totalFootnotesLength += noteLength;
269
        }
365
        }
270
    }
366
    }
271
367
368
    /** {@inheritDoc} */
272
    protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
369
    protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
273
        int returnValue = super.restartFrom(restartingNode, currentIndex);
370
        int returnValue = super.restartFrom(restartingNode, currentIndex);
274
        newFootnotes = false;
371
        newFootnotes = false;
Lines 276-285 Link Here
276
            // remove from footnotesList the note lists that will be met
373
            // remove from footnotesList the note lists that will be met
277
            // after the restarting point
374
            // after the restarting point
278
            for (int j = currentIndex; j >= restartingNode.position; j--) {
375
            for (int j = currentIndex; j >= restartingNode.position; j--) {
279
                KnuthElement resettedElement = getElement(j);
376
                final KnuthElement resetElement = getElement(j);
280
                if (resettedElement instanceof KnuthBlockBox
377
                if (resetElement instanceof KnuthBlockBox
281
                    && ((KnuthBlockBox) resettedElement).hasAnchors()) {
378
                    && ((KnuthBlockBox) resetElement).hasAnchors()) {
282
                    resetFootnotes(((KnuthBlockBox) resettedElement).getElementLists());
379
                    resetFootnotes(((KnuthBlockBox) resetElement).getElementLists());
283
                }
380
                }
284
            }
381
            }
285
        }
382
        }
Lines 288-299 Link Here
288
385
289
    private void resetFootnotes(List elementLists) {
386
    private void resetFootnotes(List elementLists) {
290
        for (int i = 0; i < elementLists.size(); i++) {
387
        for (int i = 0; i < elementLists.size(); i++) {
291
            /*LinkedList removedList = (LinkedList)*/footnotesList.remove(footnotesList.size() - 1);
388
            /*LinkedList removedList = (LinkedList)*/ListUtil.removeLast(footnotesList);
292
            lengthList.remove(lengthList.size() - 1);
389
            ListUtil.removeLast(lengthList);
293
390
294
            // update totalFootnotesLength
391
            // update totalFootnotesLength
295
            if (lengthList.size() > 0) {
392
            if (!lengthList.isEmpty()) {
296
                totalFootnotesLength = ((Integer) lengthList.get(lengthList.size() - 1)).intValue();
393
                totalFootnotesLength = ((Integer) ListUtil.getLast(lengthList)).intValue();
297
            } else {
394
            } else {
298
                totalFootnotesLength = 0;
395
                totalFootnotesLength = 0;
299
            }
396
            }
Lines 304-319 Link Here
304
        }
401
        }
305
    }
402
    }
306
403
404
    /** {@inheritDoc} */
307
    protected void considerLegalBreak(KnuthElement element, int elementIdx) {
405
    protected void considerLegalBreak(KnuthElement element, int elementIdx) {
406
        if (element.isPenalty()) {
407
            int breakClass = ((KnuthPenalty) element).getBreakClass();
408
            switch (breakClass) {
409
            case Constants.EN_COLUMN:
410
            case Constants.EN_PAGE:
411
                if (this.currentKeepContext != breakClass) {
412
                    this.lastBeforeKeepContextSwitch = getLastTooShort();
413
                }
414
                this.currentKeepContext = breakClass;
415
                break;
416
            case Constants.EN_AUTO:
417
                this.currentKeepContext = breakClass;
418
                break;
419
            default:
420
                //nop
421
            }
422
        }
308
        super.considerLegalBreak(element, elementIdx);
423
        super.considerLegalBreak(element, elementIdx);
309
        newFootnotes = false;
424
        newFootnotes = false;
310
    }
425
    }
311
426
427
    /** {@inheritDoc} */
428
    protected boolean elementCanEndLine(KnuthElement element, int line) {
429
        if (!(element.isPenalty()) || pageProvider == null) {
430
            return true;
431
        } else {
432
            KnuthPenalty p = (KnuthPenalty) element;
433
            if (p.getP() <= 0) {
434
                return true;
435
            } else {
436
                int context = p.getBreakClass();
437
                switch (context) {
438
                case Constants.EN_LINE:
439
                case Constants.EN_COLUMN:
440
                    return p.getP() < KnuthPenalty.INFINITE;
441
                case Constants.EN_PAGE:
442
                    return p.getP() < KnuthPenalty.INFINITE
443
                            || !pageProvider.endPage(line - 1);
444
                case Constants.EN_AUTO:
445
                    log.warn("keep is not auto but context is");
446
                    return true;
447
                default:
448
                    if (p.getP() < KnuthPenalty.INFINITE) {
449
                        log.warn("Non recognized keep context:" + context);
450
                        return true;
451
                    } else {
452
                        return false;
453
                    }
454
                }
455
            }
456
        }
457
    }
458
459
    /** {@inheritDoc} */
312
    protected int computeDifference(KnuthNode activeNode, KnuthElement element,
460
    protected int computeDifference(KnuthNode activeNode, KnuthElement element,
313
                                    int elementIndex) {
461
                                    int elementIndex) {
314
        KnuthPageNode pageNode = (KnuthPageNode) activeNode;
462
        KnuthPageNode pageNode = (KnuthPageNode) activeNode;
315
        int actualWidth = totalWidth - pageNode.totalWidth;
463
        int actualWidth = totalWidth - pageNode.totalWidth;
316
        int footnoteSplit;
464
        int footnoteSplit = 0;
317
        boolean canDeferOldFootnotes;
465
        boolean canDeferOldFootnotes;
318
        if (element.isPenalty()) {
466
        if (element.isPenalty()) {
319
            actualWidth += element.getW();
467
            actualWidth += element.getW();
Lines 332-338 Link Here
332
                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
480
                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
333
                    footnoteListIndex = footnotesList.size() - 1;
481
                    footnoteListIndex = footnotesList.size() - 1;
334
                    footnoteElementIndex
482
                    footnoteElementIndex
335
                        = ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1;
483
                        = getFootnoteList(footnoteListIndex).size() - 1;
336
                } else if (((canDeferOldFootnotes
484
                } else if (((canDeferOldFootnotes
337
                                = checkCanDeferOldFootnotes(pageNode, elementIndex))
485
                                = checkCanDeferOldFootnotes(pageNode, elementIndex))
338
                            || newFootnotes)
486
                            || newFootnotes)
Lines 358-364 Link Here
358
                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
506
                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
359
                    footnoteListIndex = footnotesList.size() - 1;
507
                    footnoteListIndex = footnotesList.size() - 1;
360
                    footnoteElementIndex
508
                    footnoteElementIndex
361
                        = ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1;
509
                        = getFootnoteList(footnoteListIndex).size() - 1;
362
                }
510
                }
363
            } else {
511
            } else {
364
                // all footnotes have already been placed on previous pages
512
                // all footnotes have already been placed on previous pages
Lines 375-381 Link Here
375
        }
523
        }
376
    }
524
    }
377
525
378
    /** Checks whether footnotes from preceding pages may be deferred to the page after
526
    /**
527
     * Checks whether footnotes from preceding pages may be deferred to the page after
379
     * the given element.
528
     * the given element.
380
     * @param node active node for the preceding page break
529
     * @param node active node for the preceding page break
381
     * @param contentElementIndex index of the Knuth element considered for the
530
     * @param contentElementIndex index of the Knuth element considered for the
Lines 448-454 Link Here
448
        return ((newFootnotes
597
        return ((newFootnotes
449
                 && firstNewFootnoteIndex != 0
598
                 && firstNewFootnoteIndex != 0
450
                 && (listIndex < firstNewFootnoteIndex - 1
599
                 && (listIndex < firstNewFootnoteIndex - 1
451
                     || elementIndex < ((LinkedList) footnotesList.get(listIndex)).size() - 1))
600
                     || elementIndex < getFootnoteList(listIndex).size() - 1))
452
                || length < totalFootnotesLength);
601
                || length < totalFootnotesLength);
453
    }
602
    }
454
603
Lines 457-462 Link Here
457
     * @param activeNode currently considered previous page break
606
     * @param activeNode currently considered previous page break
458
     * @param availableLength available space for footnotes
607
     * @param availableLength available space for footnotes
459
     * @param canDeferOldFootnotes
608
     * @param canDeferOldFootnotes
609
     * @return ...
460
     */
610
     */
461
    private int getFootnoteSplit(KnuthPageNode activeNode, int availableLength,
611
    private int getFootnoteSplit(KnuthPageNode activeNode, int availableLength,
462
                boolean canDeferOldFootnotes) {
612
                boolean canDeferOldFootnotes) {
Lines 473-478 Link Here
473
     * @param prevLength total length of footnotes inserted so far
623
     * @param prevLength total length of footnotes inserted so far
474
     * @param availableLength available space for footnotes on this page
624
     * @param availableLength available space for footnotes on this page
475
     * @param canDeferOldFootnotes
625
     * @param canDeferOldFootnotes
626
     * @return ...
476
     */
627
     */
477
    private int getFootnoteSplit(int prevListIndex, int prevElementIndex, int prevLength,
628
    private int getFootnoteSplit(int prevListIndex, int prevElementIndex, int prevLength,
478
                                 int availableLength, boolean canDeferOldFootnotes) {
629
                                 int availableLength, boolean canDeferOldFootnotes) {
Lines 491-497 Link Here
491
            // already placed in a page: advance to the next element
642
            // already placed in a page: advance to the next element
492
            int listIndex = prevListIndex;
643
            int listIndex = prevListIndex;
493
            int elementIndex = prevElementIndex;
644
            int elementIndex = prevElementIndex;
494
            if (elementIndex == ((LinkedList) footnotesList.get(listIndex)).size() - 1) {
645
            if (elementIndex == getFootnoteList(listIndex).size() - 1) {
495
                listIndex++;
646
                listIndex++;
496
                elementIndex = 0;
647
                elementIndex = 0;
497
            } else {
648
            } else {
Lines 524-531 Link Here
524
            }
675
            }
525
676
526
            // try adding a split of the next note
677
            // try adding a split of the next note
527
            noteListIterator = ((LinkedList) footnotesList.get(listIndex))
678
            noteListIterator = getFootnoteList(listIndex).listIterator(elementIndex);
528
                    .listIterator(elementIndex);
529
679
530
            int prevSplitLength = 0;
680
            int prevSplitLength = 0;
531
            int prevIndex = -1;
681
            int prevIndex = -1;
Lines 539-545 Link Here
539
                    prevIndex = index;
689
                    prevIndex = index;
540
                }
690
                }
541
                // get a sub-sequence from the note element list
691
                // get a sub-sequence from the note element list
542
                boolean bPrevIsBox = false;
692
                boolean boxPreceding = false;
543
                while (noteListIterator.hasNext()) {
693
                while (noteListIterator.hasNext()) {
544
                    // as this method is called only if it is not possible to insert
694
                    // as this method is called only if it is not possible to insert
545
                    // all footnotes, and we have already tried (and failed) to insert
695
                    // all footnotes, and we have already tried (and failed) to insert
Lines 549-579 Link Here
549
                    if (element.isBox()) {
699
                    if (element.isBox()) {
550
                        // element is a box
700
                        // element is a box
551
                        splitLength += element.getW();
701
                        splitLength += element.getW();
552
                        bPrevIsBox = true;
702
                        boxPreceding = true;
553
                    } else if (element.isGlue()) {
703
                    } else if (element.isGlue()) {
554
                        // element is a glue
704
                        // element is a glue
555
                        if (bPrevIsBox) {
705
                        if (boxPreceding) {
556
                            // end of the sub-sequence
706
                            // end of the sub-sequence
557
                            index = noteListIterator.previousIndex();
707
                            index = noteListIterator.previousIndex();
558
                            break;
708
                            break;
559
                        }
709
                        }
560
                        bPrevIsBox = false;
710
                        boxPreceding = false;
561
                        splitLength += element.getW();
711
                        splitLength += element.getW();
562
                    } else {
712
                    } else {
563
                        // element is a penalty
713
                        // element is a penalty
564
                        if (element.getP() < KnuthElement.INFINITE) {
714
                        //if (element.getP() < KnuthElement.INFINITE) {
565
                            // end of the sub-sequence
715
                            // end of the sub-sequence
566
                            index = noteListIterator.previousIndex();
716
                            index = noteListIterator.previousIndex();
567
                            break;
717
                            break;
568
                        }
718
                        //}
569
                    }
719
                    }
570
                }
720
                }
571
            }
721
            }
722
572
            // if prevSplitLength is 0, this means that the available length isn't enough
723
            // if prevSplitLength is 0, this means that the available length isn't enough
573
            // to insert even the smallest split of the last footnote, so we cannot end a
724
            // to insert even the smallest split of the last footnote, so we cannot end a
574
            // page here
725
            // page here
575
            // if prevSplitLength is > 0 we can insert some footnote content in this page
726
            // if prevSplitLength is > 0 we can insert some footnote content in this page
576
            // and insert the remaining in the following one
727
            // and insert the remaining in the following one
728
            //TODO: check this conditional, as the first one is always false...?
577
            if (!somethingAdded) {
729
            if (!somethingAdded) {
578
                // there was not enough space to add a piece of the first new footnote
730
                // there was not enough space to add a piece of the first new footnote
579
                // this is not a good break
731
                // this is not a good break
Lines 583-594 Link Here
583
                footnoteListIndex = (prevIndex != -1) ? listIndex : listIndex - 1;
735
                footnoteListIndex = (prevIndex != -1) ? listIndex : listIndex - 1;
584
                footnoteElementIndex = (prevIndex != -1)
736
                footnoteElementIndex = (prevIndex != -1)
585
                    ? prevIndex
737
                    ? prevIndex
586
                    : ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1;
738
                    : getFootnoteList(footnoteListIndex).size() - 1;
587
            }
739
            }
588
            return prevSplitLength;
740
            return prevSplitLength;
589
        }
741
        }
590
    }
742
    }
591
743
744
    /** {@inheritDoc} */
592
    protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
745
    protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
593
        // compute the adjustment ratio
746
        // compute the adjustment ratio
594
        if (difference > 0) {
747
        if (difference > 0) {
Lines 618-623 Link Here
618
        }
771
        }
619
    }
772
    }
620
773
774
    /** {@inheritDoc} */
621
    protected double computeDemerits(KnuthNode activeNode, KnuthElement element,
775
    protected double computeDemerits(KnuthNode activeNode, KnuthElement element,
622
                                    int fitnessClass, double r) {
776
                                    int fitnessClass, double r) {
623
        double demerits = 0;
777
        double demerits = 0;
Lines 625-631 Link Here
625
        double f = Math.abs(r);
779
        double f = Math.abs(r);
626
        f = 1 + 100 * f * f * f;
780
        f = 1 + 100 * f * f * f;
627
        if (element.isPenalty() && element.getP() >= 0) {
781
        if (element.isPenalty() && element.getP() >= 0) {
628
            f += element.getP();
782
            if (element.getP() < KnuthPenalty.INFINITE) {
783
                f += element.getP();
784
            }
629
            demerits = f * f;
785
            demerits = f * f;
630
        } else if (element.isPenalty() && !element.isForcedBreak()) {
786
        } else if (element.isPenalty() && !element.isForcedBreak()) {
631
            double penalty = element.getP();
787
            double penalty = element.getP();
Lines 654-660 Link Here
654
            }
810
            }
655
            if (footnoteListIndex < footnotesList.size()) {
811
            if (footnoteListIndex < footnotesList.size()) {
656
                if (footnoteElementIndex
812
                if (footnoteElementIndex
657
                        < ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1) {
813
                        < getFootnoteList(footnoteListIndex).size() - 1) {
658
                    // add demerits for the footnote split between pages
814
                    // add demerits for the footnote split between pages
659
                    demerits += splitFootnoteDemerits;
815
                    demerits += splitFootnoteDemerits;
660
                }
816
                }
Lines 680-706 Link Here
680
    }
836
    }
681
837
682
    private void createFootnotePages(KnuthPageNode lastNode) {
838
    private void createFootnotePages(KnuthPageNode lastNode) {
839
683
        insertedFootnotesLength = lastNode.totalFootnotes;
840
        insertedFootnotesLength = lastNode.totalFootnotes;
684
        footnoteListIndex = lastNode.footnoteListIndex;
841
        footnoteListIndex = lastNode.footnoteListIndex;
685
        footnoteElementIndex = lastNode.footnoteElementIndex;
842
        footnoteElementIndex = lastNode.footnoteElementIndex;
686
        int availableBPD = getLineWidth(lastNode.line);
843
        int availableBPD = getLineWidth(lastNode.line);
687
        int split = 0;
844
        int split = 0;
845
        int tmpLength = -1;
688
        KnuthPageNode prevNode = lastNode;
846
        KnuthPageNode prevNode = lastNode;
689
847
690
        // create pages containing the remaining footnote bodies
848
        // create pages containing the remaining footnote bodies
691
        while (insertedFootnotesLength < totalFootnotesLength) {
849
        while (insertedFootnotesLength < totalFootnotesLength) {
850
            tmpLength = ((Integer) lengthList.get(footnoteListIndex)).intValue();
692
            // try adding some more content
851
            // try adding some more content
693
            if (((Integer) lengthList.get(footnoteListIndex)).intValue() - insertedFootnotesLength
852
            if ((tmpLength - insertedFootnotesLength) <= availableBPD) {
694
                <= availableBPD) {
695
                // add a whole footnote
853
                // add a whole footnote
696
                availableBPD -= ((Integer) lengthList.get(footnoteListIndex)).intValue()
854
                availableBPD -= tmpLength - insertedFootnotesLength;
697
                                - insertedFootnotesLength;
855
                insertedFootnotesLength = tmpLength;
698
                insertedFootnotesLength = ((Integer)lengthList.get(footnoteListIndex)).intValue();
699
                footnoteElementIndex
856
                footnoteElementIndex
700
                    = ((LinkedList)footnotesList.get(footnoteListIndex)).size() - 1;
857
                    = getFootnoteList(footnoteListIndex).size() - 1;
701
            } else if ((split = getFootnoteSplit(footnoteListIndex, footnoteElementIndex,
858
            } else if ((split = getFootnoteSplit(footnoteListIndex, footnoteElementIndex,
702
                                                 insertedFootnotesLength, availableBPD, true))
859
                                     insertedFootnotesLength, availableBPD, true))
703
                       > 0) {
860
                    > 0) {
704
                // add a piece of a footnote
861
                // add a piece of a footnote
705
                availableBPD -= split;
862
                availableBPD -= split;
706
                insertedFootnotesLength += split;
863
                insertedFootnotesLength += split;
Lines 732-743 Link Here
732
    }
889
    }
733
890
734
    /**
891
    /**
735
     * @return a list of PageBreakPosition elements
892
     * @return a list of {@link PageBreakPosition} elements
893
     *          corresponding to the computed page- and column-breaks
736
     */
894
     */
737
    public LinkedList getPageBreaks() {
895
    public LinkedList getPageBreaks() {
738
        return pageBreaks;
896
        return pageBreaks;
739
    }
897
    }
740
898
899
    /**
900
     * Insert the given {@link PageBreakPosition} as the first
901
     * element in the list of page-breaks
902
     *
903
     * @param pageBreak the position to insert
904
     */
741
    public void insertPageBreakAsFirst(PageBreakPosition pageBreak) {
905
    public void insertPageBreakAsFirst(PageBreakPosition pageBreak) {
742
        if (pageBreaks == null) {
906
        if (pageBreaks == null) {
743
            pageBreaks = new LinkedList();
907
            pageBreaks = new LinkedList();
Lines 759-767 Link Here
759
        }
923
        }
760
    }
924
    }
761
925
926
    /** {@inheritDoc} */
762
    public void updateData1(int total, double demerits) {
927
    public void updateData1(int total, double demerits) {
763
    }
928
    }
764
929
930
    /** {@inheritDoc} */
765
    public void updateData2(KnuthNode bestActiveNode,
931
    public void updateData2(KnuthNode bestActiveNode,
766
                            KnuthSequence sequence,
932
                            KnuthSequence sequence,
767
                            int total) {
933
                            int total) {
Lines 807-813 Link Here
807
        int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
973
        int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
808
        int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
974
        int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
809
        if (footnotesList != null
975
        if (footnotesList != null
810
            && firstElementIndex == ((LinkedList) footnotesList.get(firstListIndex)).size() - 1) {
976
            && firstElementIndex == getFootnoteList(firstListIndex).size() - 1) {
811
            // advance to the next list
977
            // advance to the next list
812
            firstListIndex++;
978
            firstListIndex++;
813
            firstElementIndex = 0;
979
            firstElementIndex = 0;
Lines 829-834 Link Here
829
                ratio, difference));
995
                ratio, difference));
830
    }
996
    }
831
997
998
    /** {@inheritDoc} */
832
    protected int filterActiveNodes() {
999
    protected int filterActiveNodes() {
833
        // leave only the active node with fewest total demerits
1000
        // leave only the active node with fewest total demerits
834
        KnuthNode bestActiveNode = null;
1001
        KnuthNode bestActiveNode = null;
Lines 848-858 Link Here
848
                }
1015
                }
849
            }
1016
            }
850
        }
1017
        }
851
        return bestActiveNode.line;
1018
        return (bestActiveNode == null) ? -1 : bestActiveNode.line;
852
    }
1019
    }
853
1020
854
    public LinkedList getFootnoteList(int index) {
1021
    /**
855
        return (LinkedList) footnotesList.get(index);
1022
     * Obtain the element-list corresponding to the footnote at the given index.
1023
     *
1024
     * @param index the index in the list of footnotes
1025
     * @return  the element-list
1026
     */
1027
    protected final List getFootnoteList(int index) {
1028
        return (List) footnotesList.get(index);
856
    }
1029
    }
857
1030
858
    /** @return the associated top-level formatting object. */
1031
    /** @return the associated top-level formatting object. */
(-)src/java/org/apache/fop/layoutmgr/PageProvider.java (-1 / +44 lines)
Lines 146-152 Link Here
146
        return this.lastReportedBPD;
146
        return this.lastReportedBPD;
147
    }
147
    }
148
148
149
    // Wish there were a more elegant way to do this in Java
150
    private int[] getColIndexAndColCount(int index) {
151
        int columnCount = 0;
152
        int colIndex = startColumnOfCurrentElementList + index;
153
        int pageIndex = -1;
154
        do {
155
            colIndex -= columnCount;
156
            pageIndex++;
157
            Page page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
158
            columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
159
        } while (colIndex >= columnCount);
160
        return new int[] {colIndex, columnCount};
161
    }
162
149
    /**
163
    /**
164
     * Checks if a break at the passed index would start a new page
165
     * @param index the index of the element before the break
166
     * @return  {@code true} if the break starts a new page
167
     */
168
    boolean startPage(int index) {
169
        return getColIndexAndColCount(index)[0] == 0;
170
    }
171
172
    /**
173
     * Checks if a break at the passed index would end a page
174
     * @param index the index of the element before the break
175
     * @return  {@code true} if the break ends a page
176
     */
177
    boolean endPage(int index) {
178
        int[] colIndexAndColCount = getColIndexAndColCount(index);
179
        return colIndexAndColCount[0] == colIndexAndColCount[1] - 1;
180
    }
181
182
    /**
183
     * Obtain the applicable column-count for the element at the
184
     * passed index
185
     * @param index the index of the element
186
     * @return  the number of columns
187
     */
188
    int getColumnCount(int index) {
189
        return getColIndexAndColCount(index)[1];
190
    }
191
192
    /**
150
     * Returns the part index (0<x<partCount) which denotes the first part on the last page
193
     * Returns the part index (0<x<partCount) which denotes the first part on the last page
151
     * generated by the current element list.
194
     * generated by the current element list.
152
     * @param partCount Number of parts determined by the breaking algorithm
195
     * @param partCount Number of parts determined by the breaking algorithm
Lines 272-275 Link Here
272
        return page;
315
        return page;
273
    }
316
    }
274
317
275
}
318
}
(-)src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java (-10 / +7 lines)
Lines 29-38 Link Here
29
import org.apache.fop.area.Area;
29
import org.apache.fop.area.Area;
30
import org.apache.fop.area.Block;
30
import org.apache.fop.area.Block;
31
import org.apache.fop.fo.flow.ListBlock;
31
import org.apache.fop.fo.flow.ListBlock;
32
import org.apache.fop.fo.properties.KeepProperty;
32
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
33
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
33
import org.apache.fop.layoutmgr.ConditionalElementListener;
34
import org.apache.fop.layoutmgr.ConditionalElementListener;
34
import org.apache.fop.layoutmgr.ElementListUtils;
35
import org.apache.fop.layoutmgr.ElementListUtils;
35
import org.apache.fop.layoutmgr.KeepUtil;
36
import org.apache.fop.layoutmgr.LayoutContext;
36
import org.apache.fop.layoutmgr.LayoutContext;
37
import org.apache.fop.layoutmgr.LayoutManager;
37
import org.apache.fop.layoutmgr.LayoutManager;
38
import org.apache.fop.layoutmgr.NonLeafPosition;
38
import org.apache.fop.layoutmgr.NonLeafPosition;
Lines 279-299 Link Here
279
    }
279
    }
280
280
281
    /** {@inheritDoc} */
281
    /** {@inheritDoc} */
282
    public int getKeepTogetherStrength() {
282
    public KeepProperty getKeepTogetherProperty() {
283
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
283
        return getListBlockFO().getKeepTogether();
284
                getListBlockFO().getKeepTogether());
285
        strength = Math.max(strength, getParentKeepTogetherStrength());
286
        return strength;
287
    }
284
    }
288
285
289
    /** {@inheritDoc} */
286
    /** {@inheritDoc} */
290
    public int getKeepWithNextStrength() {
287
    public KeepProperty getKeepWithPreviousProperty() {
291
        return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithNext());
288
        return getListBlockFO().getKeepWithPrevious();
292
    }
289
    }
293
290
294
    /** {@inheritDoc} */
291
    /** {@inheritDoc} */
295
    public int getKeepWithPreviousStrength() {
292
    public KeepProperty getKeepWithNextProperty() {
296
        return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithPrevious());
293
        return getListBlockFO().getKeepWithNext();
297
    }
294
    }
298
295
299
    /** {@inheritDoc} */
296
    /** {@inheritDoc} */
(-)src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (-23 / +19 lines)
Lines 32-44 Link Here
32
import org.apache.fop.fo.flow.ListItem;
32
import org.apache.fop.fo.flow.ListItem;
33
import org.apache.fop.fo.flow.ListItemBody;
33
import org.apache.fop.fo.flow.ListItemBody;
34
import org.apache.fop.fo.flow.ListItemLabel;
34
import org.apache.fop.fo.flow.ListItemLabel;
35
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
35
import org.apache.fop.fo.properties.KeepProperty;
36
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
36
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
37
import org.apache.fop.layoutmgr.BreakElement;
37
import org.apache.fop.layoutmgr.BreakElement;
38
import org.apache.fop.layoutmgr.ConditionalElementListener;
38
import org.apache.fop.layoutmgr.ConditionalElementListener;
39
import org.apache.fop.layoutmgr.ElementListObserver;
39
import org.apache.fop.layoutmgr.ElementListObserver;
40
import org.apache.fop.layoutmgr.ElementListUtils;
40
import org.apache.fop.layoutmgr.ElementListUtils;
41
import org.apache.fop.layoutmgr.KeepUtil;
41
import org.apache.fop.layoutmgr.Keep;
42
import org.apache.fop.layoutmgr.KnuthBlockBox;
42
import org.apache.fop.layoutmgr.KnuthBlockBox;
43
import org.apache.fop.layoutmgr.KnuthBox;
43
import org.apache.fop.layoutmgr.KnuthBox;
44
import org.apache.fop.layoutmgr.KnuthElement;
44
import org.apache.fop.layoutmgr.KnuthElement;
Lines 83-90 Link Here
83
    private MinOptMax effSpaceBefore;
83
    private MinOptMax effSpaceBefore;
84
    private MinOptMax effSpaceAfter;
84
    private MinOptMax effSpaceAfter;
85
85
86
    private int keepWithNextPendingOnLabel;
86
    private Keep keepWithNextPendingOnLabel;
87
    private int keepWithNextPendingOnBody;
87
    private Keep keepWithNextPendingOnBody;
88
88
89
    private int listItemHeight;
89
    private int listItemHeight;
90
90
Lines 254-261 Link Here
254
254
255
        context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
255
        context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
256
        context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
256
        context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
257
        context.updateKeepWithNextPending(getKeepWithNextStrength());
257
        context.updateKeepWithNextPending(getKeepWithNext());
258
        context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
258
        context.updateKeepWithPreviousPending(getKeepWithPrevious());
259
259
260
        setFinished(true);
260
        setFinished(true);
261
        resetSpaces();
261
        resetSpaces();
Lines 276-291 Link Here
276
        int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
276
        int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
277
        int step;
277
        int step;
278
        int addedBoxHeight = 0;
278
        int addedBoxHeight = 0;
279
        int keepWithNextActive = BlockLevelLayoutManager.KEEP_AUTO;
279
        Keep keepWithNextActive = Keep.KEEP_AUTO;
280
280
281
        LinkedList returnList = new LinkedList();
281
        LinkedList returnList = new LinkedList();
282
        while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {
282
        while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {
283
283
284
            if (end[0] + 1 == elementLists[0].size()) {
284
            if (end[0] + 1 == elementLists[0].size()) {
285
                keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnLabel);
285
                keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel);
286
            }
286
            }
287
            if (end[1] + 1 == elementLists[1].size()) {
287
            if (end[1] + 1 == elementLists[1].size()) {
288
                keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnBody);
288
                keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody);
289
            }
289
            }
290
290
291
            // compute penalty height and box height
291
            // compute penalty height and box height
Lines 339-352 Link Here
339
            }
339
            }
340
340
341
            if (addedBoxHeight < totalHeight) {
341
            if (addedBoxHeight < totalHeight) {
342
                int strength = BlockLevelLayoutManager.KEEP_AUTO;
342
                Keep keep = keepWithNextActive.compare(getKeepTogether());
343
                strength = Math.max(strength, keepWithNextActive);
344
                strength = Math.max(strength, getKeepTogetherStrength());
345
                int p = stepPenalty;
343
                int p = stepPenalty;
346
                if (p > -KnuthElement.INFINITE) {
344
                if (p > -KnuthElement.INFINITE) {
347
                    p = Math.max(p, KeepUtil.getPenaltyForKeep(strength));
345
                    p = Math.max(p, keep.getPenalty());
348
                }
346
                }
349
                returnList.add(new BreakElement(stepPosition, penaltyHeight, p, -1, context));
347
                returnList.add(new BreakElement(stepPosition, penaltyHeight, p, keep.getContext(),
348
                        context));
350
            }
349
            }
351
        }
350
        }
352
351
Lines 644-664 Link Here
644
    }
643
    }
645
644
646
    /** {@inheritDoc} */
645
    /** {@inheritDoc} */
647
    public int getKeepTogetherStrength() {
646
    public KeepProperty getKeepTogetherProperty() {
648
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
647
        return getListItemFO().getKeepTogether();
649
                getListItemFO().getKeepTogether());
650
        strength = Math.max(strength, getParentKeepTogetherStrength());
651
        return strength;
652
    }
648
    }
653
649
654
    /** {@inheritDoc} */
650
    /** {@inheritDoc} */
655
    public int getKeepWithNextStrength() {
651
    public KeepProperty getKeepWithPreviousProperty() {
656
        return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithNext());
652
        return getListItemFO().getKeepWithPrevious();
657
    }
653
    }
658
654
659
    /** {@inheritDoc} */
655
    /** {@inheritDoc} */
660
    public int getKeepWithPreviousStrength() {
656
    public KeepProperty getKeepWithNextProperty() {
661
        return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithPrevious());
657
        return getListItemFO().getKeepWithNext();
662
    }
658
    }
663
659
664
    /** {@inheritDoc} */
660
    /** {@inheritDoc} */
(-)src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (-9 / +8 lines)
Lines 28-35 Link Here
28
import org.apache.fop.fo.flow.AbstractListItemPart;
28
import org.apache.fop.fo.flow.AbstractListItemPart;
29
import org.apache.fop.fo.flow.ListItemBody;
29
import org.apache.fop.fo.flow.ListItemBody;
30
import org.apache.fop.fo.flow.ListItemLabel;
30
import org.apache.fop.fo.flow.ListItemLabel;
31
import org.apache.fop.fo.properties.KeepProperty;
31
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
32
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
32
import org.apache.fop.layoutmgr.KeepUtil;
33
import org.apache.fop.layoutmgr.Keep;
33
import org.apache.fop.layoutmgr.LayoutContext;
34
import org.apache.fop.layoutmgr.LayoutContext;
34
import org.apache.fop.layoutmgr.LayoutManager;
35
import org.apache.fop.layoutmgr.LayoutManager;
35
import org.apache.fop.layoutmgr.NonLeafPosition;
36
import org.apache.fop.layoutmgr.NonLeafPosition;
Lines 221-240 Link Here
221
    }
222
    }
222
223
223
    /** {@inheritDoc} */
224
    /** {@inheritDoc} */
224
    public int getKeepTogetherStrength() {
225
    public KeepProperty getKeepTogetherProperty() {
225
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getPartFO().getKeepTogether());
226
        return getPartFO().getKeepTogether();
226
        strength = Math.max(strength, getParentKeepTogetherStrength());
227
        return strength;
228
    }
227
    }
229
228
230
    /** {@inheritDoc} */
229
    /** {@inheritDoc} */
231
    public int getKeepWithNextStrength() {
230
    public Keep getKeepWithNext() {
232
        return KEEP_AUTO;
231
        return Keep.KEEP_AUTO;
233
    }
232
    }
234
233
235
    /** {@inheritDoc} */
234
    /** {@inheritDoc} */
236
    public int getKeepWithPreviousStrength() {
235
    public Keep getKeepWithPrevious() {
237
        return KEEP_AUTO;
236
        return Keep.KEEP_AUTO;
238
    }
237
    }
239
238
240
}
239
}
(-)src/java/org/apache/fop/layoutmgr/table/ActiveCell.java (-7 / +11 lines)
Lines 32-39 Link Here
32
import org.apache.fop.fo.flow.table.EffRow;
32
import org.apache.fop.fo.flow.table.EffRow;
33
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
33
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
34
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
34
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
35
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
36
import org.apache.fop.layoutmgr.ElementListUtils;
35
import org.apache.fop.layoutmgr.ElementListUtils;
36
import org.apache.fop.layoutmgr.Keep;
37
import org.apache.fop.layoutmgr.KnuthBlockBox;
37
import org.apache.fop.layoutmgr.KnuthBlockBox;
38
import org.apache.fop.layoutmgr.KnuthBox;
38
import org.apache.fop.layoutmgr.KnuthBox;
39
import org.apache.fop.layoutmgr.KnuthElement;
39
import org.apache.fop.layoutmgr.KnuthElement;
Lines 75-81 Link Here
75
    /** True if the next CellPart that will be created will be the last one for this cell. */
75
    /** True if the next CellPart that will be created will be the last one for this cell. */
76
    private boolean lastCellPart;
76
    private boolean lastCellPart;
77
77
78
    private int keepWithNextStrength;
78
    private Keep keepWithNext;
79
79
80
    private int spanIndex = 0;
80
    private int spanIndex = 0;
81
81
Lines 218-224 Link Here
218
        includedLength = -1;  // Avoid troubles with cells having content of zero length
218
        includedLength = -1;  // Avoid troubles with cells having content of zero length
219
        totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
219
        totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
220
        endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
220
        endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
221
        keepWithNextStrength = BlockLevelLayoutManager.KEEP_AUTO;
221
        keepWithNext = Keep.KEEP_AUTO;
222
        remainingLength = totalLength - previousRowsLength;
222
        remainingLength = totalLength - previousRowsLength;
223
223
224
        afterNextStep = new Step(previousRowsLength);
224
        afterNextStep = new Step(previousRowsLength);
Lines 314-320 Link Here
314
            KnuthElement el = (KnuthElement) knuthIter.next();
314
            KnuthElement el = (KnuthElement) knuthIter.next();
315
            if (el.isPenalty()) {
315
            if (el.isPenalty()) {
316
                prevIsBox = false;
316
                prevIsBox = false;
317
                if (el.getP() < KnuthElement.INFINITE) {
317
                if (el.getP() < KnuthElement.INFINITE
318
                        || ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) {
319
                    // TODO too much is being done in that test, only to handle
320
                    // keep.within-column properly.
321
318
                    // First legal break point
322
                    // First legal break point
319
                    breakFound = true;
323
                    breakFound = true;
320
                    KnuthPenalty p = (KnuthPenalty) el;
324
                    KnuthPenalty p = (KnuthPenalty) el;
Lines 533-539 Link Here
533
     */
537
     */
534
    CellPart createCellPart() {
538
    CellPart createCellPart() {
535
        if (nextStep.end + 1 == elementList.size()) {
539
        if (nextStep.end + 1 == elementList.size()) {
536
            keepWithNextStrength = pgu.getKeepWithNextStrength();
540
            keepWithNext = pgu.getKeepWithNext();
537
            // TODO if keep-with-next is set on the row, must every cell of the row
541
            // TODO if keep-with-next is set on the row, must every cell of the row
538
            // contribute some content from children blocks?
542
            // contribute some content from children blocks?
539
            // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/
543
            // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/
Lines 576-583 Link Here
576
        }
580
        }
577
    }
581
    }
578
582
579
    int getKeepWithNextStrength() {
583
    Keep getKeepWithNext() {
580
        return keepWithNextStrength;
584
        return keepWithNext;
581
    }
585
    }
582
586
583
    int getPenaltyValue() {
587
    int getPenaltyValue() {
(-)src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (-11 / +10 lines)
Lines 35-44 Link Here
35
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
35
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
36
import org.apache.fop.fo.flow.table.Table;
36
import org.apache.fop.fo.flow.table.Table;
37
import org.apache.fop.fo.flow.table.TablePart;
37
import org.apache.fop.fo.flow.table.TablePart;
38
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
39
import org.apache.fop.layoutmgr.BreakElement;
38
import org.apache.fop.layoutmgr.BreakElement;
40
import org.apache.fop.layoutmgr.ElementListUtils;
39
import org.apache.fop.layoutmgr.ElementListUtils;
41
import org.apache.fop.layoutmgr.KeepUtil;
40
import org.apache.fop.layoutmgr.Keep;
42
import org.apache.fop.layoutmgr.KnuthBox;
41
import org.apache.fop.layoutmgr.KnuthBox;
43
import org.apache.fop.layoutmgr.KnuthElement;
42
import org.apache.fop.layoutmgr.KnuthElement;
44
import org.apache.fop.layoutmgr.KnuthGlue;
43
import org.apache.fop.layoutmgr.KnuthGlue;
Lines 213-225 Link Here
213
        context.clearKeepsPending();
212
        context.clearKeepsPending();
214
        context.setBreakBefore(Constants.EN_AUTO);
213
        context.setBreakBefore(Constants.EN_AUTO);
215
        context.setBreakAfter(Constants.EN_AUTO);
214
        context.setBreakAfter(Constants.EN_AUTO);
216
        int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
215
        Keep keepWithPrevious = Keep.KEEP_AUTO;
217
        int breakBefore = Constants.EN_AUTO;
216
        int breakBefore = Constants.EN_AUTO;
218
        if (rowGroup != null) {
217
        if (rowGroup != null) {
219
            RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
218
            RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
220
                    stepper);
219
                    stepper);
221
            List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
220
            List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
222
            keepWithPrevious = Math.max(keepWithPrevious, context.getKeepWithPreviousPending());
221
            keepWithPrevious = keepWithPrevious.compare(context.getKeepWithPreviousPending());
223
            breakBefore = context.getBreakBefore();
222
            breakBefore = context.getBreakBefore();
224
            int breakBetween = context.getBreakAfter();
223
            int breakBetween = context.getBreakAfter();
225
            returnList.addAll(nextRowGroupElems);
224
            returnList.addAll(nextRowGroupElems);
Lines 228-234 Link Here
228
227
229
                //Note previous pending keep-with-next and clear the strength
228
                //Note previous pending keep-with-next and clear the strength
230
                //(as the layout context is reused)
229
                //(as the layout context is reused)
231
                int keepWithNextPending = context.getKeepWithNextPending();
230
                Keep keepWithNextPending = context.getKeepWithNextPending();
232
                context.clearKeepWithNextPending();
231
                context.clearKeepWithNextPending();
233
232
234
                //Get elements for next row group
233
                //Get elements for next row group
Lines 246-262 Link Here
246
                 */
245
                 */
247
246
248
                //Determine keep constraints
247
                //Determine keep constraints
249
                int penaltyStrength = BlockLevelLayoutManager.KEEP_AUTO;
248
                Keep keep = keepWithNextPending.compare(context.getKeepWithPreviousPending());
250
                penaltyStrength = Math.max(penaltyStrength, keepWithNextPending);
251
                penaltyStrength = Math.max(penaltyStrength, context.getKeepWithPreviousPending());
252
                context.clearKeepWithPreviousPending();
249
                context.clearKeepWithPreviousPending();
253
                penaltyStrength = Math.max(penaltyStrength, getTableLM().getKeepTogetherStrength());
250
                keep = keep.compare(getTableLM().getKeepTogether());
254
                int penaltyValue = KeepUtil.getPenaltyForKeep(penaltyStrength);
251
                int penaltyValue = keep.getPenalty();
252
                int breakClass = keep.getContext();
255
253
256
                breakBetween = BreakUtil.compareBreakClasses(breakBetween,
254
                breakBetween = BreakUtil.compareBreakClasses(breakBetween,
257
                        context.getBreakBefore());
255
                        context.getBreakBefore());
258
                if (breakBetween != Constants.EN_AUTO) {
256
                if (breakBetween != Constants.EN_AUTO) {
259
                    penaltyValue = -KnuthElement.INFINITE;
257
                    penaltyValue = -KnuthElement.INFINITE;
258
                    breakClass = breakBetween;
260
                }
259
                }
261
                BreakElement breakElement;
260
                BreakElement breakElement;
262
                ListIterator elemIter = returnList.listIterator(returnList.size());
261
                ListIterator elemIter = returnList.listIterator(returnList.size());
Lines 267-273 Link Here
267
                    breakElement = (BreakElement) elem;
266
                    breakElement = (BreakElement) elem;
268
                }
267
                }
269
                breakElement.setPenaltyValue(penaltyValue);
268
                breakElement.setPenaltyValue(penaltyValue);
270
                breakElement.setBreakClass(breakBetween);
269
                breakElement.setBreakClass(breakClass);
271
                returnList.addAll(nextRowGroupElems);
270
                returnList.addAll(nextRowGroupElems);
272
                breakBetween = context.getBreakAfter();
271
                breakBetween = context.getBreakAfter();
273
            }
272
            }
(-)src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java (-2 / +2 lines)
Lines 60-67 Link Here
60
        LinkedList returnList = new LinkedList();
60
        LinkedList returnList = new LinkedList();
61
        createElementsForRowGroup(context, alignment, bodyType, returnList);
61
        createElementsForRowGroup(context, alignment, bodyType, returnList);
62
62
63
        context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPreviousStrength());
63
        context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPrevious());
64
        context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNextStrength());
64
        context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNext());
65
65
66
        int breakBefore = Constants.EN_AUTO;
66
        int breakBefore = Constants.EN_AUTO;
67
        TableRow firstRow = rowGroup[0].getTableRow();
67
        TableRow firstRow = rowGroup[0].getTableRow();
(-)src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (-11 / +9 lines)
Lines 35-45 Link Here
35
import org.apache.fop.fo.FObj;
35
import org.apache.fop.fo.FObj;
36
import org.apache.fop.fo.flow.table.Table;
36
import org.apache.fop.fo.flow.table.Table;
37
import org.apache.fop.fo.flow.table.TableColumn;
37
import org.apache.fop.fo.flow.table.TableColumn;
38
import org.apache.fop.fo.properties.KeepProperty;
38
import org.apache.fop.layoutmgr.BlockLevelEventProducer;
39
import org.apache.fop.layoutmgr.BlockLevelEventProducer;
39
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
40
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
40
import org.apache.fop.layoutmgr.BreakElement;
41
import org.apache.fop.layoutmgr.BreakElement;
41
import org.apache.fop.layoutmgr.ConditionalElementListener;
42
import org.apache.fop.layoutmgr.ConditionalElementListener;
42
import org.apache.fop.layoutmgr.KeepUtil;
43
import org.apache.fop.layoutmgr.KnuthElement;
43
import org.apache.fop.layoutmgr.KnuthElement;
44
import org.apache.fop.layoutmgr.KnuthGlue;
44
import org.apache.fop.layoutmgr.KnuthGlue;
45
import org.apache.fop.layoutmgr.LayoutContext;
45
import org.apache.fop.layoutmgr.LayoutContext;
Lines 256-265 Link Here
256
        log.debug(contentKnuthElements);
256
        log.debug(contentKnuthElements);
257
        wrapPositionElements(contentKnuthElements, returnList);
257
        wrapPositionElements(contentKnuthElements, returnList);
258
258
259
        context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
259
        context.updateKeepWithPreviousPending(getKeepWithPrevious());
260
        context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
260
        context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
261
261
262
        context.updateKeepWithNextPending(getKeepWithNextStrength());
262
        context.updateKeepWithNextPending(getKeepWithNext());
263
        context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
263
        context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
264
264
265
        if (getTable().isSeparateBorderModel()) {
265
        if (getTable().isSeparateBorderModel()) {
Lines 448-467 Link Here
448
    }
448
    }
449
449
450
    /** {@inheritDoc} */
450
    /** {@inheritDoc} */
451
    public int getKeepTogetherStrength() {
451
    public KeepProperty getKeepTogetherProperty() {
452
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepTogether());
452
        return getTable().getKeepTogether();
453
        strength = Math.max(strength, getParentKeepTogetherStrength());
454
        return strength;
455
    }
453
    }
456
454
457
    /** {@inheritDoc} */
455
    /** {@inheritDoc} */
458
    public int getKeepWithNextStrength() {
456
    public KeepProperty getKeepWithPreviousProperty() {
459
        return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithNext());
457
        return getTable().getKeepWithPrevious();
460
    }
458
    }
461
459
462
    /** {@inheritDoc} */
460
    /** {@inheritDoc} */
463
    public int getKeepWithPreviousStrength() {
461
    public KeepProperty getKeepWithNextProperty() {
464
        return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithPrevious());
462
        return getTable().getKeepWithNext();
465
    }
463
    }
466
464
467
    // --------- Property Resolution related functions --------- //
465
    // --------- Property Resolution related functions --------- //
(-)src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (-18 / +18 lines)
Lines 24-29 Link Here
24
24
25
import org.apache.commons.logging.Log;
25
import org.apache.commons.logging.Log;
26
import org.apache.commons.logging.LogFactory;
26
import org.apache.commons.logging.LogFactory;
27
27
import org.apache.fop.area.Area;
28
import org.apache.fop.area.Area;
28
import org.apache.fop.area.Block;
29
import org.apache.fop.area.Block;
29
import org.apache.fop.area.Trait;
30
import org.apache.fop.area.Trait;
Lines 31-46 Link Here
31
import org.apache.fop.fo.flow.table.GridUnit;
32
import org.apache.fop.fo.flow.table.GridUnit;
32
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
33
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
33
import org.apache.fop.fo.flow.table.Table;
34
import org.apache.fop.fo.flow.table.Table;
34
import org.apache.fop.fo.flow.table.TablePart;
35
import org.apache.fop.fo.flow.table.TableCell;
35
import org.apache.fop.fo.flow.table.TableCell;
36
import org.apache.fop.fo.flow.table.TableColumn;
36
import org.apache.fop.fo.flow.table.TableColumn;
37
import org.apache.fop.fo.flow.table.TablePart;
37
import org.apache.fop.fo.flow.table.TableRow;
38
import org.apache.fop.fo.flow.table.TableRow;
38
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
39
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
39
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
40
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
40
import org.apache.fop.layoutmgr.AreaAdditionUtil;
41
import org.apache.fop.layoutmgr.AreaAdditionUtil;
41
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
42
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
42
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
43
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
43
import org.apache.fop.layoutmgr.KeepUtil;
44
import org.apache.fop.layoutmgr.ElementListUtils;
45
import org.apache.fop.layoutmgr.Keep;
44
import org.apache.fop.layoutmgr.KnuthBox;
46
import org.apache.fop.layoutmgr.KnuthBox;
45
import org.apache.fop.layoutmgr.KnuthElement;
47
import org.apache.fop.layoutmgr.KnuthElement;
46
import org.apache.fop.layoutmgr.KnuthGlue;
48
import org.apache.fop.layoutmgr.KnuthGlue;
Lines 153-163 Link Here
153
                log.debug("child LM signals pending keep with next");
155
                log.debug("child LM signals pending keep with next");
154
            }
156
            }
155
            if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
157
            if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
156
                primaryGridUnit.setKeepWithPreviousStrength(childLC.getKeepWithPreviousPending());
158
                primaryGridUnit.setKeepWithPrevious(childLC.getKeepWithPreviousPending());
157
                childLC.clearKeepWithPreviousPending();
159
                childLC.clearKeepWithPreviousPending();
158
            }
160
            }
159
161
160
            if (prevLM != null) {
162
            if (prevLM != null
163
                    && !ElementListUtils.endsWithForcedBreak(contentList)) {
161
                // there is a block handled by prevLM
164
                // there is a block handled by prevLM
162
                // before the one handled by curLM
165
                // before the one handled by curLM
163
                addInBetweenBreak(contentList, context, childLC);
166
                addInBetweenBreak(contentList, context, childLC);
Lines 174-180 Link Here
174
            }
177
            }
175
            prevLM = curLM;
178
            prevLM = curLM;
176
        }
179
        }
177
        primaryGridUnit.setKeepWithNextStrength(context.getKeepWithNextPending());
180
        primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending());
178
181
179
        returnedList = new LinkedList();
182
        returnedList = new LinkedList();
180
        if (!contentList.isEmpty()) {
183
        if (!contentList.isEmpty()) {
Lines 195-201 Link Here
195
        }
198
        }
196
        final KnuthElement lastItem = (KnuthElement) ListUtil
199
        final KnuthElement lastItem = (KnuthElement) ListUtil
197
                .getLast(returnList);
200
                .getLast(returnList);
198
        if (((KnuthElement) lastItem).isForcedBreak()) {
201
        if (lastItem.isForcedBreak()) {
199
            KnuthPenalty p = (KnuthPenalty) lastItem;
202
            KnuthPenalty p = (KnuthPenalty) lastItem;
200
            primaryGridUnit.setBreakAfter(p.getBreakClass());
203
            primaryGridUnit.setBreakAfter(p.getBreakClass());
201
            p.setP(0);
204
            p.setP(0);
Lines 556-581 Link Here
556
    }
559
    }
557
560
558
    /** {@inheritDoc} */
561
    /** {@inheritDoc} */
559
    public int getKeepTogetherStrength() {
562
    public Keep getKeepTogether() {
560
        int strength = KEEP_AUTO;
563
        Keep keep = Keep.KEEP_AUTO;
561
        if (primaryGridUnit.getRow() != null) {
564
        if (primaryGridUnit.getRow() != null) {
562
            strength = Math.max(strength, KeepUtil.getKeepStrength(
565
            keep = Keep.getKeep(primaryGridUnit.getRow().getKeepTogether());
563
                    primaryGridUnit.getRow().getKeepTogether().getWithinPage()));
564
            strength = Math.max(strength, KeepUtil.getKeepStrength(
565
                    primaryGridUnit.getRow().getKeepTogether().getWithinColumn()));
566
        }
566
        }
567
        strength = Math.max(strength, getParentKeepTogetherStrength());
567
        keep = keep.compare(getParentKeepTogether());
568
        return strength;
568
        return keep;
569
    }
569
    }
570
570
571
    /** {@inheritDoc} */
571
    /** {@inheritDoc} */
572
    public int getKeepWithNextStrength() {
572
    public Keep getKeepWithNext() {
573
        return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!)
573
        return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!)
574
    }
574
    }
575
575
576
    /** {@inheritDoc} */
576
    /** {@inheritDoc} */
577
    public int getKeepWithPreviousStrength() {
577
    public Keep getKeepWithPrevious() {
578
        return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!)
578
        return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!)
579
    }
579
    }
580
580
581
    // --------- Property Resolution related functions --------- //
581
    // --------- Property Resolution related functions --------- //
(-)src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java (-16 / +6 lines)
Lines 23-28 Link Here
23
import org.apache.fop.area.Block;
23
import org.apache.fop.area.Block;
24
import org.apache.fop.fo.flow.table.TableAndCaption;
24
import org.apache.fop.fo.flow.table.TableAndCaption;
25
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
25
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
26
import org.apache.fop.layoutmgr.Keep;
26
import org.apache.fop.layoutmgr.LayoutContext;
27
import org.apache.fop.layoutmgr.LayoutContext;
27
import org.apache.fop.layoutmgr.PositionIterator;
28
import org.apache.fop.layoutmgr.PositionIterator;
28
29
Lines 201-232 Link Here
201
    }
202
    }
202
203
203
    /** {@inheritDoc} */
204
    /** {@inheritDoc} */
204
    public int getKeepTogetherStrength() {
205
    public Keep getKeepWithNext() {
205
        int strength = KEEP_AUTO;
206
        return Keep.KEEP_AUTO;
206
        /* TODO Complete me!
207
        /* TODO Complete me!
207
        int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
208
                getTableAndCaptionFO().getKeepTogether());
209
        */
210
        strength = Math.max(strength, getParentKeepTogetherStrength());
211
        return strength;
212
    }
213
214
    /** {@inheritDoc} */
215
    public int getKeepWithNextStrength() {
216
        return KEEP_AUTO;
217
        /* TODO Complete me!
218
        return KeepUtil.getCombinedBlockLevelKeepStrength(
208
        return KeepUtil.getCombinedBlockLevelKeepStrength(
219
                getTableAndCaptionFO().getKeepWithNext());
209
                getTableAndCaptionFO().getKeepWithNext());
220
        */
210
        */
221
    }
211
    }
222
212
223
    /** {@inheritDoc} */
213
    /** {@inheritDoc} */
224
    public int getKeepWithPreviousStrength() {
214
    public Keep getKeepWithPrevious() {
225
        return KEEP_AUTO;
215
        return Keep.KEEP_AUTO;
226
        /* TODO Complete me!
216
        /* TODO Complete me!
227
        return KeepUtil.getCombinedBlockLevelKeepStrength(
217
        return KeepUtil.getCombinedBlockLevelKeepStrength(
228
                getTableAndCaptionFO().getKeepWithPrevious());
218
                getTableAndCaptionFO().getKeepWithPrevious());
229
        */
219
        */
230
    }
220
    }
231
221
232
}
222
}
(-)src/java/org/apache/fop/layoutmgr/table/TableStepper.java (-16 / +12 lines)
Lines 30-41 Link Here
30
import org.apache.fop.fo.flow.table.EffRow;
30
import org.apache.fop.fo.flow.table.EffRow;
31
import org.apache.fop.fo.flow.table.GridUnit;
31
import org.apache.fop.fo.flow.table.GridUnit;
32
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
32
import org.apache.fop.fo.flow.table.PrimaryGridUnit;
33
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
34
import org.apache.fop.layoutmgr.BreakElement;
33
import org.apache.fop.layoutmgr.BreakElement;
35
import org.apache.fop.layoutmgr.KeepUtil;
34
import org.apache.fop.layoutmgr.Keep;
36
import org.apache.fop.layoutmgr.KnuthBlockBox;
35
import org.apache.fop.layoutmgr.KnuthBlockBox;
37
import org.apache.fop.layoutmgr.KnuthBox;
36
import org.apache.fop.layoutmgr.KnuthBox;
38
import org.apache.fop.layoutmgr.KnuthElement;
39
import org.apache.fop.layoutmgr.KnuthGlue;
37
import org.apache.fop.layoutmgr.KnuthGlue;
40
import org.apache.fop.layoutmgr.KnuthPenalty;
38
import org.apache.fop.layoutmgr.KnuthPenalty;
41
import org.apache.fop.layoutmgr.LayoutContext;
39
import org.apache.fop.layoutmgr.LayoutContext;
Lines 241-280 Link Here
241
                }
239
                }
242
            }
240
            }
243
241
244
            int strength = BlockLevelLayoutManager.KEEP_AUTO;
242
            Keep keep = Keep.KEEP_AUTO;
245
            int stepPenalty = 0;
243
            int stepPenalty = 0;
246
            for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
244
            for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
247
                ActiveCell activeCell = (ActiveCell) iter.next();
245
                ActiveCell activeCell = (ActiveCell) iter.next();
248
                strength = Math.max(strength, activeCell.getKeepWithNextStrength());
246
                keep = keep.compare(activeCell.getKeepWithNext());
249
                stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue());
247
                stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue());
250
            }
248
            }
251
            if (!rowFinished) {
249
            if (!rowFinished) {
252
                strength = Math.max(strength, rowGroup[activeRowIndex].getKeepTogetherStrength());
250
                keep = keep.compare(rowGroup[activeRowIndex].getKeepTogether());
253
                //The above call doesn't take the penalty from the table into account, so...
251
                //The above call doesn't take the penalty from the table into account, so...
254
                strength = Math.max(strength, getTableLM().getKeepTogetherStrength());
252
                keep = keep.compare(getTableLM().getKeepTogether());
255
            } else if (activeRowIndex < rowGroup.length - 1) {
253
            } else if (activeRowIndex < rowGroup.length - 1) {
256
                strength = Math.max(strength,
254
                keep = keep.compare(rowGroup[activeRowIndex].getKeepWithNext());
257
                        rowGroup[activeRowIndex].getKeepWithNextStrength());
255
                keep = keep.compare(rowGroup[activeRowIndex + 1].getKeepWithPrevious());
258
                strength = Math.max(strength,
259
                        rowGroup[activeRowIndex + 1].getKeepWithPreviousStrength());
260
                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
256
                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
261
                        rowGroup[activeRowIndex].getBreakAfter());
257
                        rowGroup[activeRowIndex].getBreakAfter());
262
                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
258
                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
263
                        rowGroup[activeRowIndex + 1].getBreakBefore());
259
                        rowGroup[activeRowIndex + 1].getBreakBefore());
264
            }
260
            }
265
            int p = KeepUtil.getPenaltyForKeep(strength);
261
            int p = keep.getPenalty();
266
            if (rowHeightSmallerThanFirstStep) {
262
            if (rowHeightSmallerThanFirstStep) {
267
                rowHeightSmallerThanFirstStep = false;
263
                rowHeightSmallerThanFirstStep = false;
268
                p = KnuthPenalty.INFINITE;
264
                p = KnuthPenalty.INFINITE;
269
            }
265
            }
270
            if (p > -KnuthElement.INFINITE) {
266
            p = Math.max(p, stepPenalty);
271
                p = Math.max(p, stepPenalty);
267
            int breakClass = keep.getContext();
272
            }
273
            if (nextBreakClass != Constants.EN_AUTO) {
268
            if (nextBreakClass != Constants.EN_AUTO) {
274
                log.trace("Forced break encountered");
269
                log.trace("Forced break encountered");
275
                p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
270
                p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
271
                breakClass = nextBreakClass;
276
            }
272
            }
277
            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, nextBreakClass, context));
273
            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context));
278
            if (penaltyOrGlueLen < 0) {
274
            if (penaltyOrGlueLen < 0) {
279
                returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true));
275
                returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true));
280
            }
276
            }
(-)src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java (-17 / +5 lines)
Lines 23-28 Link Here
23
import org.apache.fop.area.Block;
23
import org.apache.fop.area.Block;
24
import org.apache.fop.fo.flow.table.TableCaption;
24
import org.apache.fop.fo.flow.table.TableCaption;
25
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
25
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
26
import org.apache.fop.layoutmgr.Keep;
26
import org.apache.fop.layoutmgr.LayoutContext;
27
import org.apache.fop.layoutmgr.LayoutContext;
27
import org.apache.fop.layoutmgr.PositionIterator;
28
import org.apache.fop.layoutmgr.PositionIterator;
28
29
Lines 197-226 Link Here
197
    }
198
    }
198
199
199
    /** {@inheritDoc} */
200
    /** {@inheritDoc} */
200
    public int getKeepTogetherStrength() {
201
    public Keep getKeepWithNext() {
201
        int strength = KEEP_AUTO;
202
        return Keep.KEEP_AUTO;
202
        /* TODO Complete me!
203
        /* TODO Complete me!
203
        strength = Math.max(strength, KeepUtil.getKeepStrength(
204
                getTableCaptionFO().getKeepTogether().getWithinPage()));
205
        strength = Math.max(strength, KeepUtil.getKeepStrength(
206
                getTableCaptionFO().getKeepTogether().getWithinColumn()));
207
        */
208
        strength = Math.max(strength, getParentKeepTogetherStrength());
209
        return strength;
210
    }
211
212
    /** {@inheritDoc} */
213
    public int getKeepWithNextStrength() {
214
        return KEEP_AUTO;
215
        /* TODO Complete me!
216
        return KeepUtil.getCombinedBlockLevelKeepStrength(
204
        return KeepUtil.getCombinedBlockLevelKeepStrength(
217
                getTableCaptionFO().getKeepWithNext());
205
                getTableCaptionFO().getKeepWithNext());
218
        */
206
        */
219
    }
207
    }
220
208
221
    /** {@inheritDoc} */
209
    /** {@inheritDoc} */
222
    public int getKeepWithPreviousStrength() {
210
    public Keep getKeepWithPrevious() {
223
        return KEEP_AUTO;
211
        return Keep.KEEP_AUTO;
224
        /* TODO Complete me!
212
        /* TODO Complete me!
225
        return KeepUtil.getCombinedBlockLevelKeepStrength(
213
        return KeepUtil.getCombinedBlockLevelKeepStrength(
226
                getTableCaptionFO().getKeepWithPrevious());
214
                getTableCaptionFO().getKeepWithPrevious());
(-)src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (-27 / +70 lines)
Lines 34-39 Link Here
34
import org.apache.fop.fo.properties.BreakPropertySet;
34
import org.apache.fop.fo.properties.BreakPropertySet;
35
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
35
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
36
import org.apache.fop.fo.properties.SpaceProperty;
36
import org.apache.fop.fo.properties.SpaceProperty;
37
import org.apache.fop.fo.properties.KeepProperty;
37
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
38
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
38
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
39
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
39
import org.apache.fop.traits.MinOptMax;
40
import org.apache.fop.traits.MinOptMax;
Lines 259-265 Link Here
259
260
260
        updateContentAreaIPDwithOverconstrainedAdjust();
261
        updateContentAreaIPDwithOverconstrainedAdjust();
261
262
262
        List returnedList = null;
263
        List returnedList;
263
        List contentList = new LinkedList();
264
        List contentList = new LinkedList();
264
        List returnList = new LinkedList();
265
        List returnList = new LinkedList();
265
266
Lines 274-280 Link Here
274
275
275
        if (!firstVisibleMarkServed) {
276
        if (!firstVisibleMarkServed) {
276
            addKnuthElementsForSpaceBefore(returnList, alignment);
277
            addKnuthElementsForSpaceBefore(returnList, alignment);
277
            context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
278
            context.updateKeepWithPreviousPending(getKeepWithPrevious());
278
        }
279
        }
279
280
280
        addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
281
        addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
Lines 316-322 Link Here
316
            }
317
            }
317
            if (returnedList != null
318
            if (returnedList != null
318
                    && returnedList.size() == 1
319
                    && returnedList.size() == 1
319
                    && ((ListElement) returnedList.get(0)).isForcedBreak()) {
320
                    && ElementListUtils.startsWithForcedBreak(returnedList)) {
320
321
321
                if (curLM.isFinished() && !hasNextChildLM()) {
322
                if (curLM.isFinished() && !hasNextChildLM()) {
322
                    // a descendant of this block has break-before
323
                    // a descendant of this block has break-before
Lines 342-348 Link Here
342
343
343
                // "wrap" the Position inside each element
344
                // "wrap" the Position inside each element
344
                // moving the elements from contentList to returnList
345
                // moving the elements from contentList to returnList
345
                returnedList = new LinkedList();
346
                wrapPositionElements(contentList, returnList);
346
                wrapPositionElements(contentList, returnList);
347
347
348
                return returnList;
348
                return returnList;
Lines 375-381 Link Here
375
                    }
375
                    }
376
                    /* end of extension */
376
                    /* end of extension */
377
377
378
                    returnedList = new LinkedList();
379
                    wrapPositionElements(contentList, returnList);
378
                    wrapPositionElements(contentList, returnList);
380
379
381
                    return returnList;
380
                    return returnList;
Lines 394-400 Link Here
394
        }
393
        }
395
        /* end of extension */
394
        /* end of extension */
396
395
397
        returnedList = new LinkedList();
398
        if (!contentList.isEmpty()) {
396
        if (!contentList.isEmpty()) {
399
            wrapPositionElements(contentList, returnList);
397
            wrapPositionElements(contentList, returnList);
400
        } else if (forcedBreakAfterLast == null) {
398
        } else if (forcedBreakAfterLast == null) {
Lines 417-423 Link Here
417
            returnList.add(forcedBreakAfterLast);
415
            returnList.add(forcedBreakAfterLast);
418
        }
416
        }
419
417
420
        context.updateKeepWithNextPending(getKeepWithNextStrength());
418
        context.updateKeepWithNextPending(getKeepWithNext());
421
419
422
        setFinished(true);
420
        setFinished(true);
423
421
Lines 426-456 Link Here
426
424
427
    /**
425
    /**
428
     * Adds a break element to the content list between individual child elements.
426
     * Adds a break element to the content list between individual child elements.
429
     * @param contentList the content list to populate
427
     * @param contentList
430
     * @param context the current layout context
428
     * @param parentLC
431
     * @param childLC the currently active child layout context
429
     * @param childLC the currently active child layout context
432
     */
430
     */
433
    protected void addInBetweenBreak(List contentList, LayoutContext context,
431
    protected void addInBetweenBreak(List contentList, LayoutContext parentLC,
434
            LayoutContext childLC) {
432
                                     LayoutContext childLC) {
433
435
        if (mustKeepTogether()
434
        if (mustKeepTogether()
436
                || context.isKeepWithNextPending()
435
                || parentLC.isKeepWithNextPending()
437
                || childLC.isKeepWithPreviousPending()) {
436
                || childLC.isKeepWithPreviousPending()) {
438
437
439
            int strength = getKeepTogetherStrength();
438
            Keep keep = getKeepTogether();
440
439
441
            //Handle pending keep-with-next
440
            //Handle pending keep-with-next
442
            strength = Math.max(strength, context.getKeepWithNextPending());
441
            keep = keep.compare(parentLC.getKeepWithNextPending());
443
            context.clearKeepWithNextPending();
442
            parentLC.clearKeepWithNextPending();
444
443
445
            //Handle pending keep-with-previous from child LM
444
            //Handle pending keep-with-previous from child LM
446
            strength = Math.max(strength, childLC.getKeepWithPreviousPending());
445
            keep = keep.compare(childLC.getKeepWithPreviousPending());
447
            childLC.clearKeepWithPreviousPending();
446
            childLC.clearKeepWithPreviousPending();
448
447
449
            int penalty = KeepUtil.getPenaltyForKeep(strength);
448
            int penalty = keep.getPenalty();
450
449
451
            // add a penalty to forbid or discourage a break between blocks
450
            // add a penalty to forbid or discourage a break between blocks
452
            contentList.add(new BreakElement(
451
            contentList.add(new BreakElement(
453
                    new Position(this), penalty, context));
452
                    new Position(this), penalty, keep.getContext(), parentLC));
454
            return;
453
            return;
455
        }
454
        }
456
455
Lines 481-487 Link Here
481
480
482
            // add a null penalty to allow a break between blocks
481
            // add a null penalty to allow a break between blocks
483
            contentList.add(new BreakElement(
482
            contentList.add(new BreakElement(
484
                    new Position(this), 0, context));
483
                    new Position(this), 0, parentLC));
485
        }
484
        }
486
    }
485
    }
487
486
Lines 817-852 Link Here
817
     * Retrieves and returns the keep-together strength from the parent element.
816
     * Retrieves and returns the keep-together strength from the parent element.
818
     * @return the keep-together strength
817
     * @return the keep-together strength
819
     */
818
     */
820
    protected int getParentKeepTogetherStrength() {
819
    protected Keep getParentKeepTogether() {
821
        int strength = KEEP_AUTO;
820
        Keep keep = Keep.KEEP_AUTO;
822
        if (getParent() instanceof BlockLevelLayoutManager) {
821
        if (getParent() instanceof BlockLevelLayoutManager) {
823
            strength = ((BlockLevelLayoutManager)getParent()).getKeepTogetherStrength();
822
            keep = ((BlockLevelLayoutManager)getParent()).getKeepTogether();
824
        } else if (getParent() instanceof InlineLayoutManager) {
823
        } else if (getParent() instanceof InlineLayoutManager) {
825
            if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
824
            if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
826
                strength = KEEP_ALWAYS;
825
                keep = Keep.KEEP_ALWAYS;
827
            }
826
            }
828
            //TODO Fix me
827
            //TODO Fix me
829
            //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
828
            //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
830
        }
829
        }
831
        return strength;
830
        return keep;
832
    }
831
    }
833
832
834
    /** {@inheritDoc} */
833
    /** {@inheritDoc} */
835
    public boolean mustKeepTogether() {
834
    public boolean mustKeepTogether() {
836
        return getKeepTogetherStrength() > KEEP_AUTO;
835
        return !getKeepTogether().isAuto();
837
    }
836
    }
838
837
839
    /** {@inheritDoc} */
838
    /** {@inheritDoc} */
840
    public boolean mustKeepWithPrevious() {
839
    public boolean mustKeepWithPrevious() {
841
        return getKeepWithPreviousStrength() > KEEP_AUTO;
840
        return !getKeepWithPrevious().isAuto();
842
    }
841
    }
843
842
844
    /** {@inheritDoc} */
843
    /** {@inheritDoc} */
845
    public boolean mustKeepWithNext() {
844
    public boolean mustKeepWithNext() {
846
        return getKeepWithNextStrength() > KEEP_AUTO;
845
        return !getKeepWithNext().isAuto();
847
    }
846
    }
848
847
848
    /** {@inheritDoc} */
849
    public Keep getKeepTogether() {
850
        Keep keep = Keep.getKeep(getKeepTogetherProperty());
851
        keep = keep.compare(getParentKeepTogether());
852
        return keep;
853
    }
854
855
    /** {@inheritDoc} */
856
    public Keep getKeepWithPrevious() {
857
        return Keep.getKeep(getKeepWithPreviousProperty());
858
    }
859
860
    /** {@inheritDoc} */
861
    public Keep getKeepWithNext() {
862
        return Keep.getKeep(getKeepWithNextProperty());
863
    }
864
849
    /**
865
    /**
866
     * {@inheritDoc}
867
     * Default implementation throws {@code UnsupportedOperationException}
868
     * Must be implemented by the subclass, if applicable.
869
     */
870
    public KeepProperty getKeepTogetherProperty() {
871
        throw new UnsupportedOperationException();
872
    }
873
874
    /**
875
     * {@inheritDoc}
876
     * Default implementation throws {@code UnsupportedOperationException}
877
     * Must be implemented by the subclass, if applicable.
878
     */
879
    public KeepProperty getKeepWithPreviousProperty() {
880
        throw new UnsupportedOperationException();
881
    }
882
883
    /**
884
     * {@inheritDoc}
885
     * Default implementation throws {@code UnsupportedOperationException}
886
     * Must be implemented by the subclass, if applicable.
887
     */
888
    public KeepProperty getKeepWithNextProperty() {
889
        throw new UnsupportedOperationException();
890
    }
891
892
    /**
850
     * Adds the unresolved elements for border and padding to a layout context so break
893
     * Adds the unresolved elements for border and padding to a layout context so break
851
     * possibilities can be properly constructed.
894
     * possibilities can be properly constructed.
852
     * @param context the layout context
895
     * @param context the layout context
(-)src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java (-194 / +337 lines)
Lines 22-33 Link Here
22
import org.apache.commons.logging.Log;
22
import org.apache.commons.logging.Log;
23
import org.apache.commons.logging.LogFactory;
23
import org.apache.commons.logging.LogFactory;
24
24
25
import org.apache.fop.fo.FONode;
25
import org.apache.fop.fo.Constants;
26
26
27
/**
27
/**
28
 * The set of nodes is sorted into lines indexed into activeLines.
28
 * The set of nodes is sorted into lines indexed into activeLines.
29
 * The nodes in each line are linked together in a single linked list by the
29
 * The nodes in each line are linked together in a single linked list by the
30
 * KnuthNode.next field. The activeLines array contains a link to the head of
30
 * {@link KnuthNode#next} field. The activeLines array contains a link to the head of
31
 * the linked list in index 'line*2' and a link to the tail at index 'line*2+1'.
31
 * the linked list in index 'line*2' and a link to the tail at index 'line*2+1'.
32
 * <p>
32
 * <p>
33
 * The set of active nodes can be traversed by
33
 * The set of active nodes can be traversed by
Lines 57-69 Link Here
57
    /** wrap-option = "no-wrap". */
57
    /** wrap-option = "no-wrap". */
58
    public static final int ONLY_FORCED_BREAKS = 2;
58
    public static final int ONLY_FORCED_BREAKS = 2;
59
59
60
    static class FitnessClasses {
61
        static final int VERY_TIGHT = 0;
62
        static final int TIGHT = 1;
63
        static final int LOOSE = 2;
64
        static final int VERY_LOOSE = 3;
65
66
        static final String[] NAMES = { "VERY TIGHT", "TIGHT", "LOOSE", "VERY LOOSE" };
67
    }
68
60
    // parameters of Knuth's algorithm:
69
    // parameters of Knuth's algorithm:
61
    /** Penalty value for flagged penalties. */
62
    private int flaggedPenalty = 50;
63
    /** Demerit for consecutive lines ending at flagged penalties. */
70
    /** Demerit for consecutive lines ending at flagged penalties. */
64
    protected int repeatedFlaggedDemerit = 50;
71
    protected int repeatedFlaggedDemerit = KnuthPenalty.FLAGGED_PENALTY;
65
    /** Demerit for consecutive lines belonging to incompatible fitness classes . */
72
    /** Demerit for consecutive lines belonging to incompatible fitness classes . */
66
    protected int incompatibleFitnessDemerit = 50;
73
    protected int incompatibleFitnessDemerit = KnuthPenalty.FLAGGED_PENALTY;
67
    /** Maximum number of consecutive lines ending with a flagged penalty.
74
    /** Maximum number of consecutive lines ending with a flagged penalty.
68
     * Only a value >= 1 is a significant limit.
75
     * Only a value >= 1 is a significant limit.
69
     */
76
     */
Lines 110-116 Link Here
110
    /** Alignment of the paragraph's last line. */
117
    /** Alignment of the paragraph's last line. */
111
    protected int alignmentLast;
118
    protected int alignmentLast;
112
    /** Used to handle the text-indent property (indent the first line of a paragraph). */
119
    /** Used to handle the text-indent property (indent the first line of a paragraph). */
113
    protected boolean bFirst;
120
    protected boolean indentFirstPart;
114
121
115
    /**
122
    /**
116
     * The set of active nodes in ascending line order. For each line l, activeLines[2l] contains a
123
     * The set of active nodes in ascending line order. For each line l, activeLines[2l] contains a
Lines 151-180 Link Here
151
158
152
    protected BestRecords best;
159
    protected BestRecords best;
153
160
154
    /** {@inheritDoc} */
155
    private boolean partOverflowRecoveryActivated = true;
161
    private boolean partOverflowRecoveryActivated = true;
156
    private KnuthNode lastRecovered;
162
    private KnuthNode lastRecovered;
157
163
158
    /**
164
    /**
159
     * Create a new instance.
165
     * Create a new instance.
160
     * @param align alignment of the paragraph/page. One of EN_START, EN_JUSTIFY, etc. For
166
     *
161
     * pages EN_BEFORE, EN_AFTER are mapped to the corresponding inline properties
167
     * @param align     alignment of the paragraph/page. One of {@link Constants#EN_START},
162
     * (EN_START, EN_END)
168
     *                  {@link Constants#EN_JUSTIFY}, {@link Constants#EN_CENTER},
169
     *                  {@link Constants#EN_END}.
170
     *                  For pages, {@link Constants#EN_BEFORE} and {@link Constants#EN_AFTER}
171
     *                  are mapped to the corresponding inline properties,
172
     *                  {@link Constants#EN_START} and {@link Constants#EN_END}.
163
     * @param alignLast alignment of the paragraph's last line
173
     * @param alignLast alignment of the paragraph's last line
164
     * @param first for the text-indent property (indent the first line of a paragraph)
174
     * @param first     for the text-indent property ({@code true} if the first line
165
     * @param partOverflowRecovery true if too long elements should be moved to the next line/part
175
     *                  of a paragraph should be indented)
166
     * @param maxFlagCount maximum allowed number of consecutive lines ending at a flagged penalty
176
     * @param partOverflowRecovery  {@code true} if too long elements should be moved to
167
     * item
177
     *                              the next line/part
178
     * @param maxFlagCount  maximum allowed number of consecutive lines ending at a flagged penalty
179
     *                      item
168
     */
180
     */
169
    public BreakingAlgorithm(int align, int alignLast,
181
    public BreakingAlgorithm(int align, int alignLast,
170
                             boolean first, boolean partOverflowRecovery,
182
                             boolean first, boolean partOverflowRecovery,
171
                             int maxFlagCount) {
183
                             int maxFlagCount) {
172
        alignment = align;
184
        this.alignment = align;
173
        alignmentLast = alignLast;
185
        this.alignmentLast = alignLast;
174
        bFirst = first;
186
        this.indentFirstPart = first;
175
        this.partOverflowRecoveryActivated = partOverflowRecovery;
187
        this.partOverflowRecoveryActivated = partOverflowRecovery;
176
        this.best = new BestRecords();
188
        this.best = new BestRecords();
177
        maxFlaggedPenaltiesCount = maxFlagCount;
189
        this.maxFlaggedPenaltiesCount = maxFlagCount;
178
    }
190
    }
179
191
180
192
Lines 249-255 Link Here
249
            return "<KnuthNode at " + position + " "
261
            return "<KnuthNode at " + position + " "
250
                    + totalWidth + "+" + totalStretch + "-" + totalShrink
262
                    + totalWidth + "+" + totalStretch + "-" + totalShrink
251
                    + " line:" + line + " prev:" + (previous != null ? previous.position : -1)
263
                    + " line:" + line + " prev:" + (previous != null ? previous.position : -1)
252
                    + " dem:" + totalDemerits + ">";
264
                    + " dem:" + totalDemerits
265
                    + " fitness:" + FitnessClasses.NAMES[fitness] + ">";
253
        }
266
        }
254
    }
267
    }
255
268
Lines 386-392 Link Here
386
     * one of the optimal breakpoints
399
     * one of the optimal breakpoints
387
     * @param sequence the corresponding paragraph
400
     * @param sequence the corresponding paragraph
388
     * @param total the number of lines into which the paragraph will be broken
401
     * @param total the number of lines into which the paragraph will be broken
389
     * @see #calculateBreakPoints(KnuthNode, KnuthSequence, int)
390
     */
402
     */
391
    public abstract void updateData2(KnuthNode bestActiveNode,
403
    public abstract void updateData2(KnuthNode bestActiveNode,
392
                                     KnuthSequence sequence,
404
                                     KnuthSequence sequence,
Lines 404-416 Link Here
404
        return findBreakingPoints(par, 0, threshold, force, allowedBreaks);
416
        return findBreakingPoints(par, 0, threshold, force, allowedBreaks);
405
    }
417
    }
406
418
407
    /** Finds an optimal set of breakpoints for the given paragraph.
419
    /**
408
     * @param par the paragraph to break
420
     * Finds an optimal set of breakpoints for the given paragraph.
409
     * @param startIndex index of the Knuth element at which the breaking must start
421
     *
410
     * @param threshold upper bound of the adjustment ratio
422
     * @param par           the paragraph to break
411
     * @param force true if a set of breakpoints must be found even if there are no
423
     * @param startIndex    index of the Knuth element at which the breaking must start
412
     * feasible ones
424
     * @param threshold     upper bound of the adjustment ratio
413
     * @param allowedBreaks one of ONLY_FORCED_BREAKS, NO_FLAGGED_PENALTIES, ALL_BREAKS
425
     * @param force         {@code true} if a set of breakpoints must be found, even
426
     *                      if there are no feasible ones
427
     * @param allowedBreaks the type(s) of breaks allowed. One of {@link #ONLY_FORCED_BREAKS},
428
     *                      {@link #NO_FLAGGED_PENALTIES} or {@link #ALL_BREAKS}.
429
     *
430
     * @return  the number of effective breaks
414
     */
431
     */
415
    public int findBreakingPoints(KnuthSequence par, int startIndex,
432
    public int findBreakingPoints(KnuthSequence par, int startIndex,
416
                                  double threshold, boolean force,
433
                                  double threshold, boolean force,
Lines 418-559 Link Here
418
        this.par = par;
435
        this.par = par;
419
        this.threshold = threshold;
436
        this.threshold = threshold;
420
        this.force = force;
437
        this.force = force;
421
        //this.lineWidth = lineWidth;
438
439
        // initialize the algorithm
422
        initialize();
440
        initialize();
423
441
424
        activeLines = new KnuthNode[20];
425
426
        // reset lastTooShort and lastTooLong, as they could be not null
427
        // because of previous calls to findBreakingPoints
428
        lastTooShort = lastTooLong = null;
429
        // reset startLine and endLine
430
        startLine = endLine = 0;
431
        // current element in the paragraph
432
        KnuthElement thisElement = null;
433
        // previous element in the paragraph is a KnuthBox?
442
        // previous element in the paragraph is a KnuthBox?
434
        boolean previousIsBox = false;
443
        boolean previousIsBox = false;
435
444
436
        // index of the first KnuthBox in the sequence
445
        // index of the first KnuthBox in the sequence, in case of non-centered
437
        int firstBoxIndex = startIndex;
446
        // alignment. For centered alignment, we need to take into account preceding
438
        if (alignment != org.apache.fop.fo.Constants.EN_CENTER) {
447
        // penalties+glues used for the filler spaces
439
            while (par.size() > firstBoxIndex
448
        if (alignment != Constants.EN_CENTER) {
440
                    && !((KnuthElement) par.get(firstBoxIndex)).isBox()) {
449
            startIndex = par.getFirstBoxIndex();
441
                firstBoxIndex++;
442
            }
443
        }
450
        }
451
        startIndex = (startIndex == -1) ? 0 : startIndex;
444
452
445
        // create an active node representing the starting point
453
        // create an active node representing the starting point
446
        activeLines = new KnuthNode[20];
454
        addNode(0, createNode(startIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
447
        addNode(0, createNode(firstBoxIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
455
        KnuthNode lastForced = getNode(0);
448
456
457
449
        if (log.isTraceEnabled()) {
458
        if (log.isTraceEnabled()) {
450
            log.trace("Looping over " + (par.size() - startIndex) + " elements");
459
            log.trace("Looping over " + (par.size() - startIndex) + " elements");
460
            log.trace(par);
451
        }
461
        }
452
462
453
        KnuthNode lastForced = getNode(0);
463
        // main loop
464
        int elementIndex = startIndex;
465
        while (!isEndOfParagraph(elementIndex)) {
454
466
455
        // main loop
467
            previousIsBox = handleElementAt(
456
        for (int i = startIndex; i < par.size(); i++) {
468
                    elementIndex, previousIsBox, allowedBreaks).isBox();
457
            thisElement = getElement(i);
469
458
            if (thisElement.isBox()) {
459
                // a KnuthBox object is not a legal line break
460
                totalWidth += thisElement.getW();
461
                previousIsBox = true;
462
                handleBox((KnuthBox) thisElement);
463
            } else if (thisElement.isGlue()) {
464
                // a KnuthGlue object is a legal line break
465
                // only if the previous object is a KnuthBox
466
                // consider these glues according to the value of allowedBreaks
467
                if (previousIsBox
468
                    && !(allowedBreaks == ONLY_FORCED_BREAKS)) {
469
                    considerLegalBreak(thisElement, i);
470
                }
471
                totalWidth += thisElement.getW();
472
                totalStretch += thisElement.getY();
473
                totalShrink += thisElement.getZ();
474
                previousIsBox = false;
475
            } else {
476
                // a KnuthPenalty is a legal line break
477
                // only if its penalty is not infinite;
478
                // consider all penalties, non-flagged penalties or non-forcing penalties
479
                // according to the value of allowedBreaks
480
                if (((KnuthPenalty) thisElement).getP() < KnuthElement.INFINITE
481
                    && (!(allowedBreaks == NO_FLAGGED_PENALTIES)
482
                            || !(((KnuthPenalty) thisElement).isFlagged()))
483
                    && (!(allowedBreaks == ONLY_FORCED_BREAKS)
484
                            || ((KnuthPenalty) thisElement).getP() == -KnuthElement.INFINITE)) {
485
                    considerLegalBreak(thisElement, i);
486
                }
487
                previousIsBox = false;
488
            }
489
            if (activeNodeCount == 0) {
470
            if (activeNodeCount == 0) {
471
490
                if (!force) {
472
                if (!force) {
491
                    log.debug("Could not find a set of breaking points " + threshold);
473
                    log.debug("Could not find a set of breaking points " + threshold);
492
                    return 0;
474
                    return 0;
493
                }
475
                }
476
494
                // lastDeactivated was a "good" break, while lastTooShort and lastTooLong
477
                // lastDeactivated was a "good" break, while lastTooShort and lastTooLong
495
                // were "bad" breaks since the beginning;
478
                // were "bad" breaks since the beginning;
496
                // if it is not the node we just restarted from, lastDeactivated can
479
                // if it is not the node we just restarted from, lastDeactivated can
497
                // replace either lastTooShort or lastTooLong
480
                // replace either lastTooShort or lastTooLong
498
                if (lastDeactivated != null && lastDeactivated != lastForced) {
481
                if (lastDeactivated != null && lastDeactivated != lastForced) {
499
                    if (lastDeactivated.adjustRatio > 0) {
482
                    replaceLastDeactivated();
500
                        lastTooShort = lastDeactivated;
501
                    } else {
502
                        lastTooLong = lastDeactivated;
503
                    }
504
                }
483
                }
505
                if (lastTooShort == null || lastForced.position == lastTooShort.position) {
484
506
                    if (isPartOverflowRecoveryActivated()) {
485
                if (lastTooShort == null
507
                        if (this.lastRecovered == null) {
486
                        || lastForced.position == lastTooShort.position) {
508
                            this.lastRecovered = lastTooLong;
487
                    lastForced = recoverFromOverflow();
509
                            if (log.isDebugEnabled()) {
510
                                log.debug("Recovery point: " + lastRecovered);
511
                            }
512
                        }
513
                        // content would overflow, insert empty line/page and try again
514
                        KnuthNode node = createNode(
515
                                lastTooLong.previous.position, lastTooLong.previous.line + 1, 1,
516
                                0, 0, 0,
517
                                0, 0, 0,
518
                                0, 0, lastTooLong.previous);
519
                        lastForced = node;
520
                        node.fitRecoveryCounter = lastTooLong.previous.fitRecoveryCounter + 1;
521
                        if (log.isDebugEnabled()) {
522
                            log.debug("first part doesn't fit into line, recovering: "
523
                                    + node.fitRecoveryCounter);
524
                        }
525
                        if (node.fitRecoveryCounter > getMaxRecoveryAttempts()) {
526
                            while (lastForced.fitRecoveryCounter > 0) {
527
                                lastForced = lastForced.previous;
528
                                lastDeactivated = lastForced.previous;
529
                                startLine--;
530
                                endLine--;
531
                            }
532
                            lastForced = this.lastRecovered;
533
                            this.lastRecovered = null;
534
                            startLine = lastForced.line;
535
                            endLine = lastForced.line;
536
                            log.debug("rolled back...");
537
                        }
538
                    } else {
539
                        lastForced = lastTooLong;
540
                    }
541
                } else {
488
                } else {
542
                    lastForced = lastTooShort;
489
                    lastForced = lastTooShort;
543
                    this.lastRecovered = null;
490
                    this.lastRecovered = null;
544
                }
491
                }
545
492
                elementIndex = restartFrom(lastForced, elementIndex);
546
                if (log.isDebugEnabled()) {
493
            } else {
547
                    log.debug("Restarting at node " + lastForced);
494
                elementIndex++;
548
                }
549
                i = restartFrom(lastForced, i);
550
            }
495
            }
551
        }
496
        }
497
552
        finish();
498
        finish();
553
        if (log.isTraceEnabled()) {
554
            log.trace("Main loop completed " + activeNodeCount);
555
            log.trace("Active nodes=" + toString(""));
556
        }
557
499
558
        // there is at least one set of breaking points
500
        // there is at least one set of breaking points
559
        // select one or more active nodes, removing the others from the list
501
        // select one or more active nodes, removing the others from the list
Lines 571-612 Link Here
571
        return line;
513
        return line;
572
    }
514
    }
573
515
574
    /**
516
    protected KnuthNode recoverFromTooLong(KnuthNode lastTooLong) {
575
     * This method tries to find the context FO for a position in a KnuthSequence.
517
        if (log.isDebugEnabled()) {
576
     * @param seq the KnuthSequence to inspect
518
            log.debug("Recovering from too long: " + lastTooLong);
577
     * @param position the index of the position in the KnuthSequence
578
     * @return the requested context FO note or null, if no context node could be determined
579
     */
580
    private FONode findContextFO(KnuthSequence seq, int position) {
581
        ListElement el = seq.getElement(position);
582
        while (el.getLayoutManager() == null && position < seq.size() - 1) {
583
            position++;
584
            el = seq.getElement(position);
585
        }
519
        }
586
        Position pos = (el != null ? el.getPosition() : null);
520
587
        LayoutManager lm = (pos != null ? pos.getLM() : null);
521
        // content would overflow, insert empty line/page and try again
588
        while (pos instanceof NonLeafPosition) {
522
        return createNode(
589
            pos = ((NonLeafPosition)pos).getPosition();
523
                lastTooLong.previous.position, lastTooLong.previous.line + 1, 1,
590
            if (pos != null && pos.getLM() != null) {
524
                0, 0, 0,
591
                lm = pos.getLM();
525
                0, 0, 0,
592
            }
526
                0, 0, lastTooLong.previous);
593
        }
594
        if (lm != null) {
595
            return lm.getFObj();
596
        } else {
597
            return null;
598
        }
599
    }
527
    }
600
528
601
    /** Resets the algorithm's variables. */
529
    /** Initializes the algorithm's variables. */
602
    protected void initialize() {
530
    protected void initialize() {
603
        this.totalWidth = 0;
531
        this.totalWidth = 0;
604
        this.totalStretch = 0;
532
        this.totalStretch = 0;
605
        this.totalShrink = 0;
533
        this.totalShrink = 0;
534
        this.lastTooShort = this.lastTooLong = null;
535
        this.startLine = this.endLine = 0;
536
        this.activeLines = new KnuthNode[20];
606
    }
537
    }
607
538
608
    /** Creates a new active node for a feasible breakpoint at the given position. Only
539
    /**
540
     * Creates a new active node for a feasible breakpoint at the given position. Only
609
     * called in forced mode.
541
     * called in forced mode.
542
     *
610
     * @param position index of the element in the Knuth sequence
543
     * @param position index of the element in the Knuth sequence
611
     * @param line number of the line ending at the breakpoint
544
     * @param line number of the line ending at the breakpoint
612
     * @param fitness fitness class of the line ending at the breakpoint. One of 0, 1, 2, 3.
545
     * @param fitness fitness class of the line ending at the breakpoint. One of 0, 1, 2, 3.
Lines 621-626 Link Here
621
     * @param difference difference between target and actual line width
554
     * @param difference difference between target and actual line width
622
     * @param totalDemerits minimum total demerits up to the breakpoint
555
     * @param totalDemerits minimum total demerits up to the breakpoint
623
     * @param previous active node for the preceding breakpoint
556
     * @param previous active node for the preceding breakpoint
557
     * @return a new node
624
     */
558
     */
625
    protected KnuthNode createNode(int position, int line, int fitness,
559
    protected KnuthNode createNode(int position, int line, int fitness,
626
                                   int totalWidth, int totalStretch, int totalShrink,
560
                                   int totalWidth, int totalStretch, int totalShrink,
Lines 646-656 Link Here
646
                             best.getNode(fitness));
580
                             best.getNode(fitness));
647
    }
581
    }
648
582
649
    /** Empty method, hook for subclasses. */
583
    /**
584
     * Return the last node that yielded a too short line.
585
     * @return  the node corresponding to the last too short line
586
     */
587
    protected final KnuthNode getLastTooShort() {
588
        return this.lastTooShort;
589
    }
590
591
    /**
592
     * @param elementIndex  the index to check
593
     *
594
     * @return {@code true} if the given element index points to
595
     *      the end of the current paragraph, or beyond
596
     */
597
    protected final boolean isEndOfParagraph(int elementIndex) {
598
        return (elementIndex - par.size() >= 0);
599
    }
600
601
    /**
602
     * Generic handler for a {@link KnuthElement} at the given {@code position},
603
     * taking into account whether the preceding element was a box, and which
604
     * type(s) of breaks are allowed.
605
     * Non-overridable. This method simply serves to route the call to one of the
606
     * more specific handlers ({@link #handleBox(KnuthBox)},
607
     * {@link #handleGlueAt(KnuthGlue,int,boolean,int)} or
608
     * {@link #handlePenaltyAt(KnuthPenalty,int,int)}. The specialized handlers
609
     * can be overridden by subclasses to add to or modify the default behavior
610
     * for the different types of elements.
611
     *
612
     * @param position      the position index of the element in the list
613
     * @param previousIsBox {@code true} if the previous element is a box
614
     * @param allowedBreaks the type(s) of breaks allowed; should be one
615
     *                      of {@link #ALL_BREAKS}, {@link #NO_FLAGGED_PENALTIES}
616
     *                      or {@link #ONLY_FORCED_BREAKS}
617
     * @return  the handled element
618
     */
619
    protected final KnuthElement handleElementAt(int position,
620
                                                 boolean previousIsBox,
621
                                                 int allowedBreaks) {
622
        KnuthElement element = getElement(position);
623
        if (element.isBox()) {
624
            handleBox((KnuthBox) element);
625
        } else if (element.isGlue()) {
626
            handleGlueAt((KnuthGlue) element, position, previousIsBox, allowedBreaks);
627
        } else if (element.isPenalty()){
628
            handlePenaltyAt((KnuthPenalty) element, position, allowedBreaks);
629
        } else {
630
            throw new IllegalArgumentException(
631
                    "Unknown KnuthElement type: expecting KnuthBox, KnuthGlue or KnuthPenalty");
632
        }
633
        return element;
634
    }
635
636
    /**
637
     * Handle a {@link KnuthBox}.
638
     *
639
     * @param box   the {@link KnuthBox} to handle
640
     */
650
    protected void handleBox(KnuthBox box) {
641
    protected void handleBox(KnuthBox box) {
642
        // a KnuthBox object is not a legal line break,
643
        // just add the width to the total
644
        totalWidth += box.getW();
651
    }
645
    }
652
646
647
    /**
648
     * Handle a {@link KnuthGlue} at the given position,
649
     * taking into account the additional parameters.
650
     *
651
     * @param glue   the {@link KnuthGlue} to handle
652
     * @param position   the position of the glue in the list
653
     * @param previousIsBox {@code true} if the preceding element is a box
654
     * @param allowedBreaks the type of breaks that are allowed
655
     */
656
    protected void handleGlueAt(KnuthGlue glue, int position,
657
                                boolean previousIsBox, int allowedBreaks) {
658
        // a KnuthGlue object is a legal line break
659
        // only if the previous object is a KnuthBox
660
        // consider these glues according to the value of allowedBreaks
661
        if (previousIsBox
662
            && !(allowedBreaks == ONLY_FORCED_BREAKS)) {
663
            considerLegalBreak(glue, position);
664
        }
665
        totalWidth += glue.getW();
666
        totalStretch += glue.getY();
667
        totalShrink += glue.getZ();
668
    }
669
670
    /**
671
     * Handle a {@link KnuthPenalty} at the given position,
672
     * taking into account the type of breaks allowed.
673
     *
674
     * @param penalty   the {@link KnuthPenalty} to handle
675
     * @param position  the position of the penalty in the list
676
     * @param allowedBreaks the type of breaks that are allowed
677
     */
678
    protected void handlePenaltyAt(KnuthPenalty penalty, int position,
679
                                   int allowedBreaks) {
680
        // a KnuthPenalty is a legal line break
681
        // only if its penalty is not infinite;
682
        // consider all penalties, non-flagged penalties or non-forcing penalties
683
        // according to the value of allowedBreaks
684
        if (((penalty.getP() < KnuthElement.INFINITE)
685
                && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isFlagged())
686
                && (!(allowedBreaks == ONLY_FORCED_BREAKS)
687
                        || penalty.isForcedBreak()))) {
688
            considerLegalBreak(penalty, position);
689
        }
690
    }
691
692
    /**
693
     * Replace the last too-long or too-short node by the last deactivated
694
     * node, if applicable.
695
     */
696
    protected final void replaceLastDeactivated() {
697
        if (lastDeactivated.adjustRatio > 0) {
698
            //last deactivated was too short
699
            lastTooShort = lastDeactivated;
700
        } else {
701
            //last deactivated was too long or exactly the right width
702
            lastTooLong = lastDeactivated;
703
        }
704
    }
705
706
    /**
707
     * Recover from an overflow condition.
708
     *
709
     * @return  the new {@code lastForced} node
710
     */
711
    protected KnuthNode recoverFromOverflow() {
712
        KnuthNode lastForced;
713
        if (isPartOverflowRecoveryActivated()) {
714
            if (lastRecovered == null) {
715
                lastRecovered = lastTooLong;
716
                if (log.isDebugEnabled()) {
717
                    log.debug("Recovery point: " + lastRecovered);
718
                }
719
            }
720
            KnuthNode node = recoverFromTooLong(lastTooLong);
721
            lastForced = node;
722
            node.fitRecoveryCounter = lastTooLong.previous.fitRecoveryCounter + 1;
723
            if (log.isDebugEnabled()) {
724
                log.debug("first part doesn't fit into line, recovering: "
725
                        + node.fitRecoveryCounter);
726
            }
727
            if (node.fitRecoveryCounter > getMaxRecoveryAttempts()) {
728
                while (lastForced.fitRecoveryCounter > 0
729
                        && lastForced.previous != null) {
730
                    lastForced = lastForced.previous;
731
                    lastDeactivated = lastForced.previous;
732
                }
733
                lastForced = lastRecovered;
734
                lastRecovered = null;
735
                startLine = lastForced.line;
736
                endLine = lastForced.line;
737
                log.debug("rolled back...");
738
            }
739
        } else {
740
            lastForced = lastTooLong;
741
        }
742
        return lastForced;
743
    }
744
745
    /**
746
     * Restart from the given node at the given index.
747
     *
748
     * @param restartingNode    the {@link KnuthNode} to restart from
749
     * @param currentIndex      the current position index
750
     * @return  the index of the restart point
751
     */
653
    protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
752
    protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
753
        if (log.isDebugEnabled()) {
754
            log.debug("Restarting at node " + restartingNode);
755
        }
654
        restartingNode.totalDemerits = 0;
756
        restartingNode.totalDemerits = 0;
655
        addNode(restartingNode.line, restartingNode);
757
        addNode(restartingNode.line, restartingNode);
656
        startLine = restartingNode.line;
758
        startLine = restartingNode.line;
Lines 672-678 Link Here
672
        return restartingIndex;
774
        return restartingIndex;
673
    }
775
    }
674
776
675
    /** Determines if the given breakpoint is a feasible breakpoint. That is, if a decent
777
    /**
778
     * Determines if the given breakpoint is a feasible breakpoint. That is, if a decent
676
     * line may be built between one of the currently active nodes and this breakpoint.
779
     * line may be built between one of the currently active nodes and this breakpoint.
677
     * @param element the paragraph's element to consider
780
     * @param element the paragraph's element to consider
678
     * @param elementIdx the element's index inside the paragraph
781
     * @param elementIdx the element's index inside the paragraph
Lines 689-694 Link Here
689
        lastDeactivated = null;
792
        lastDeactivated = null;
690
        lastTooLong = null;
793
        lastTooLong = null;
691
        for (int line = startLine; line < endLine; line++) {
794
        for (int line = startLine; line < endLine; line++) {
795
            if (!elementCanEndLine(element, line + 1)) {
796
                continue;
797
            }
692
            for (KnuthNode node = getNode(line); node != null; node = node.next) {
798
            for (KnuthNode node = getNode(line); node != null; node = node.next) {
693
                if (node.position == elementIdx) {
799
                if (node.position == elementIdx) {
694
                    continue;
800
                    continue;
Lines 697-702 Link Here
697
                double r = computeAdjustmentRatio(node, difference);
803
                double r = computeAdjustmentRatio(node, difference);
698
                int availableShrink = totalShrink - node.totalShrink;
804
                int availableShrink = totalShrink - node.totalShrink;
699
                int availableStretch = totalStretch - node.totalStretch;
805
                int availableStretch = totalStretch - node.totalStretch;
806
700
                if (log.isTraceEnabled()) {
807
                if (log.isTraceEnabled()) {
701
                    log.trace("\tr=" + r + " difference=" + difference);
808
                    log.trace("\tr=" + r + " difference=" + difference);
702
                    log.trace("\tline=" + line);
809
                    log.trace("\tline=" + line);
Lines 704-725 Link Here
704
811
705
                // The line would be too long.
812
                // The line would be too long.
706
                if (r < -1 || element.isForcedBreak()) {
813
                if (r < -1 || element.isForcedBreak()) {
707
                    // Deactivate node.
814
                    deactivateNode(node, line);
708
                    if (log.isTraceEnabled()) {
709
                        log.trace("Removing " + node);
710
                    }
711
                    removeNode(line, node);
712
                    lastDeactivated = compareNodes(lastDeactivated, node);
713
                }
815
                }
714
816
817
                int fitnessClass = computeFitness(r);
818
                double demerits = computeDemerits(node, element, fitnessClass, r);
715
                // The line is within the available shrink and the threshold.
819
                // The line is within the available shrink and the threshold.
716
                if (r >= -1 && r <= threshold) {
820
                if (r >= -1 && r <= threshold) {
717
                    int fitnessClass = computeFitness(r);
718
                    double demerits = computeDemerits(node, element, fitnessClass, r);
719
821
720
                    if (log.isTraceEnabled()) {
822
                    if (log.isTraceEnabled()) {
721
                        log.trace("\tDemerits=" + demerits);
823
                        log.trace("\tDemerits=" + demerits);
722
                        log.trace("\tFitness class=" + fitnessClass);
824
                        log.trace("\tFitness class=" + FitnessClasses.NAMES[fitnessClass]);
723
                    }
825
                    }
724
826
725
                    if (demerits < best.getDemerits(fitnessClass)) {
827
                    if (demerits < best.getDemerits(fitnessClass)) {
Lines 733-740 Link Here
733
                // The line is way too short, but we are in forcing mode, so a node is
835
                // The line is way too short, but we are in forcing mode, so a node is
734
                // calculated and stored in lastValidNode.
836
                // calculated and stored in lastValidNode.
735
                if (force && (r <= -1 || r > threshold)) {
837
                if (force && (r <= -1 || r > threshold)) {
736
                    int fitnessClass = computeFitness(r);
737
                    double demerits = computeDemerits(node, element, fitnessClass, r);
738
                    int newWidth = totalWidth;
838
                    int newWidth = totalWidth;
739
                    int newStretch = totalStretch;
839
                    int newStretch = totalStretch;
740
                    int newShrink = totalShrink;
840
                    int newShrink = totalShrink;
Lines 759-764 Link Here
759
                    }
859
                    }
760
860
761
                    if (r <= -1) {
861
                    if (r <= -1) {
862
                        log.debug("Considering tooLong, demerits=" + demerits);
762
                        if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
863
                        if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
763
                            lastTooLong = createNode(elementIdx, line + 1, fitnessClass,
864
                            lastTooLong = createNode(elementIdx, line + 1, fitnessClass,
764
                                    newWidth, newStretch, newShrink,
865
                                    newWidth, newStretch, newShrink,
Lines 792-797 Link Here
792
    }
893
    }
793
894
794
    /**
895
    /**
896
     * Deactivate the given node
897
     *
898
     * @param node  the node
899
     * @param line  the line number
900
     */
901
    protected void deactivateNode(KnuthNode node, int line) {
902
        // Deactivate node...
903
        if (log.isTraceEnabled()) {
904
            log.trace("Removing " + node);
905
        }
906
        removeNode(line, node);
907
        // ... and remember it, if it was a good candidate
908
        lastDeactivated = compareNodes(lastDeactivated, node);
909
    }
910
911
    /**
912
     * Check if the given {@link KnuthElement} at the given line number
913
     * can end a "line" (= a "column" or "page" in page-breaking context).
914
     *
915
     * @param element   the {@link KnuthElement} to check.
916
     * @param line      the "line" number
917
     * @return  {@code true} if the given element can terminate a "line"
918
     */
919
    protected boolean elementCanEndLine(KnuthElement element, int line) {
920
        // Default implementation: the element can end a line if either it is not
921
        // a penalty, or it is a penalty with value less than KnuthElement.INFINITE.
922
        return !(element.isPenalty())
923
                || element.getP() < KnuthPenalty.INFINITE;
924
    }
925
926
    /**
795
     * Adds new active nodes for breaks at the given element.
927
     * Adds new active nodes for breaks at the given element.
796
     * @param line number of the previous line; this element will end line number (line+1)
928
     * @param line number of the previous line; this element will end line number (line+1)
797
     * @param elementIdx the element's index
929
     * @param elementIdx the element's index
Lines 832-838 Link Here
832
                // by line number and position;
964
                // by line number and position;
833
                if (log.isTraceEnabled()) {
965
                if (log.isTraceEnabled()) {
834
                    log.trace("\tInsert new break in list of " + activeNodeCount
966
                    log.trace("\tInsert new break in list of " + activeNodeCount
835
                            + " from fitness class " + i);
967
                            + " from fitness class " + FitnessClasses.NAMES[i]);
836
                }
968
                }
837
                KnuthNode newNode = createNode(elementIdx, line + 1, i,
969
                KnuthNode newNode = createNode(elementIdx, line + 1, i,
838
                                               newWidth, newStretch, newShrink);
970
                                               newWidth, newStretch, newShrink);
Lines 846-853 Link Here
846
     * Return the difference between the natural width of a line that would be made
978
     * Return the difference between the natural width of a line that would be made
847
     * between the given active node and the given element, and the available width of the
979
     * between the given active node and the given element, and the available width of the
848
     * real line.
980
     * real line.
849
     * @param activeNode node for the previous breakpoint
981
     * @param activeNode    node for the previous breakpoint
850
     * @param element currently considered breakpoint
982
     * @param element       currently considered breakpoint
983
     * @param elementIndex  index of the element that is considered as a breakpoint
851
     * @return The difference in width. Positive numbers mean extra space in the line,
984
     * @return The difference in width. Positive numbers mean extra space in the line,
852
     * negative number that the line overflows.
985
     * negative number that the line overflows.
853
     */
986
     */
Lines 862-868 Link Here
862
    }
995
    }
863
996
864
    /**
997
    /**
865
     * Return the adjust ration needed to make up for the difference. A ration of
998
     * Return the adjustment ratio needed to make up for the difference. A ratio of
866
     * <ul>
999
     * <ul>
867
     *    <li>0 means that the break has the exact right width</li>
1000
     *    <li>0 means that the break has the exact right width</li>
868
     *    <li>&gt;= -1 &amp;&amp; &lt; 0  means that the break is wider than the line,
1001
     *    <li>&gt;= -1 &amp;&amp; &lt; 0  means that the break is wider than the line,
Lines 871-879 Link Here
871
     *        but within the maximum values of the glues.</li>
1004
     *        but within the maximum values of the glues.</li>
872
     *    <li>&gt; 1 means that the break is too small to make up for the glues.</li>
1005
     *    <li>&gt; 1 means that the break is too small to make up for the glues.</li>
873
     * </ul>
1006
     * </ul>
874
     * @param activeNode
1007
     * @param activeNode    the currently active node
875
     * @param difference
1008
     * @param difference    the difference between content-length and available width
876
     * @return The ration.
1009
     * @return The adjustment ratio.
877
     */
1010
     */
878
    protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
1011
    protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
879
        // compute the adjustment ratio
1012
        // compute the adjustment ratio
Lines 901-918 Link Here
901
     * very tight or very loose).
1034
     * very tight or very loose).
902
     * See the section on "More Bells and Whistles" in Knuth's
1035
     * See the section on "More Bells and Whistles" in Knuth's
903
     * "Breaking Paragraphs Into Lines".
1036
     * "Breaking Paragraphs Into Lines".
904
     * @param r
1037
     * @param adjustRatio the adjustment ratio
905
     * @return the fitness class
1038
     * @return the fitness class
906
     */
1039
     */
907
    private int computeFitness(double r) {
1040
    private int computeFitness(double adjustRatio) {
908
        if (r < -0.5) {
1041
        if (adjustRatio < -0.5) {
909
            return 0;
1042
            return FitnessClasses.VERY_TIGHT;
910
        } else if (r <= 0.5) {
1043
        } else if (adjustRatio <= 0.5) {
911
            return 1;
1044
            return FitnessClasses.TIGHT;
912
        } else if (r <= 1) {
1045
        } else if (adjustRatio <= 1) {
913
            return 2;
1046
            return FitnessClasses.LOOSE;
914
        } else {
1047
        } else {
915
            return 3;
1048
            return FitnessClasses.VERY_LOOSE;
916
        }
1049
        }
917
    }
1050
    }
918
1051
Lines 933-944 Link Here
933
        // compute demerits
1066
        // compute demerits
934
        double f = Math.abs(r);
1067
        double f = Math.abs(r);
935
        f = 1 + 100 * f * f * f;
1068
        f = 1 + 100 * f * f * f;
936
        if (element.isPenalty() && element.getP() >= 0) {
1069
        if (element.isPenalty()) {
937
            f += element.getP();
938
            demerits = f * f;
939
        } else if (element.isPenalty() && !element.isForcedBreak()) {
940
            double penalty = element.getP();
1070
            double penalty = element.getP();
941
            demerits = f * f - penalty * penalty;
1071
            if (penalty >= 0) {
1072
                f += penalty;
1073
                demerits = f * f;
1074
            } else if (!element.isForcedBreak()) {
1075
                demerits = f * f - penalty * penalty;
1076
            }
942
        } else {
1077
        } else {
943
            demerits = f * f;
1078
            demerits = f * f;
944
        }
1079
        }
Lines 982-988 Link Here
982
        return demerits;
1117
        return demerits;
983
    }
1118
    }
984
1119
1120
    /**
1121
     * Hook for subclasses to trigger special behavior after ending the
1122
     * main loop in {@link #findBreakingPoints(KnuthSequence,int,double,boolean,int)}
1123
     */
985
    protected void finish() {
1124
    protected void finish() {
1125
        if (log.isTraceEnabled()) {
1126
            log.trace("Main loop completed " + activeNodeCount);
1127
            log.trace("Active nodes=" + toString(""));
1128
        }
986
    }
1129
    }
987
1130
988
    /**
1131
    /**
Lines 1106-1115 Link Here
1106
        sb.append("[\n");
1249
        sb.append("[\n");
1107
        for (int i = startLine; i < endLine; i++) {
1250
        for (int i = startLine; i < endLine; i++) {
1108
            for (KnuthNode node = getNode(i); node != null; node = node.next) {
1251
            for (KnuthNode node = getNode(i); node != null; node = node.next) {
1109
                sb.append(prepend + "\t" + node + ",\n");
1252
                sb.append(prepend).append('\t').append(node).append(",\n");
1110
            }
1253
            }
1111
        }
1254
        }
1112
        sb.append(prepend + "]");
1255
        sb.append(prepend).append("]");
1113
        return sb.toString();
1256
        return sb.toString();
1114
    }
1257
    }
1115
1258
(-)src/java/org/apache/fop/layoutmgr/KnuthSequence.java (-15 / +53 lines)
Lines 19-24 Link Here
19
19
20
package org.apache.fop.layoutmgr;
20
package org.apache.fop.layoutmgr;
21
21
22
import org.apache.fop.util.ListUtil;
23
22
import java.util.ArrayList;
24
import java.util.ArrayList;
23
import java.util.List;
25
import java.util.List;
24
import java.util.ListIterator;
26
import java.util.ListIterator;
Lines 26-35 Link Here
26
/**
28
/**
27
 * Represents a list of Knuth elements.
29
 * Represents a list of Knuth elements.
28
 */
30
 */
29
/**
30
 *
31
 */
32
public abstract class KnuthSequence extends ArrayList {
31
public abstract class KnuthSequence extends ArrayList {
32
33
    private int firstBoxIndex = -1;
34
33
    /**
35
    /**
34
     * Creates a new and empty list.
36
     * Creates a new and empty list.
35
     */
37
     */
Lines 132-142 Link Here
132
     * @return the last element of this sequence.
134
     * @return the last element of this sequence.
133
     */
135
     */
134
    public ListElement getLast() {
136
    public ListElement getLast() {
135
        int idx = size();
137
        return (isEmpty()
136
        if (idx == 0) {
138
                ? null
137
            return null;
139
                : (ListElement) ListUtil.getLast(this));
138
        }
139
        return (ListElement) get(idx - 1);
140
    }
140
    }
141
141
142
    /**
142
    /**
Lines 144-168 Link Here
144
     * @return the removed element.
144
     * @return the removed element.
145
     */
145
     */
146
    public ListElement removeLast() {
146
    public ListElement removeLast() {
147
        int idx = size();
147
        return (isEmpty()
148
        if (idx == 0) {
148
                ? null
149
            return null;
149
                : (ListElement) ListUtil.removeLast(this));
150
        }
151
        return (ListElement) remove(idx - 1);
152
    }
150
    }
153
151
154
    /**
152
    /**
155
     * @param index The index of the element to be returned
153
     * @param index the index of the element to be returned
156
     * @return the element at index index.
154
     * @return the element at index index.
157
     */
155
     */
158
    public ListElement getElement(int index) {
156
    public ListElement getElement(int index) {
159
        return (ListElement) get(index);
157
        return ((index >= size() || index < 0)
158
                ? null
159
                : (ListElement) get(index));
160
    }
160
    }
161
161
162
    /** @return the position index of the first box in this sequence */
163
    protected int getFirstBoxIndex() {
164
        if (isEmpty()) {
165
            firstBoxIndex = -1;
166
        } else if (firstBoxIndex == -1){
167
            //not yet initialized, or dirty
168
            firstBoxIndex = getFirstBoxIndex(0);
169
        }
170
        return firstBoxIndex;
171
    }
172
162
    /**
173
    /**
174
     * @param fromIndex the index to start from
175
     * @return  the position index of the first box, after the given position
176
     */
177
    protected int getFirstBoxIndex(int fromIndex) {
178
        if (isEmpty() || fromIndex >= size() || fromIndex < 0) {
179
            return -1;
180
        } else {
181
            ListElement element = null;
182
            int posIndex = fromIndex;
183
            int lastIndex = size() - 1;
184
            while (posIndex < lastIndex
185
                    && !(element = getElement(posIndex)).isBox()) {
186
                posIndex++;
187
            }
188
            if (element != null && element.isBox()) {
189
                return posIndex;
190
            }
191
        }
192
        return -1;
193
    }
194
195
    /**
163
     * Is this an inline or a block sequence?
196
     * Is this an inline or a block sequence?
164
     * @return true if this is an inline sequence
197
     * @return true if this is an inline sequence
165
     */
198
     */
166
    public abstract boolean isInlineSequence();
199
    public abstract boolean isInlineSequence();
167
200
201
    /** {@inheritDoc} */
202
    public String toString() {
203
        return "<KnuthSequence " + super.toString() + ">";
204
    }
205
168
}
206
}
(-)src/java/org/apache/fop/fo/flow/table/EffRow.java (-21 / +15 lines)
Lines 23-30 Link Here
23
import java.util.List;
23
import java.util.List;
24
24
25
import org.apache.fop.fo.Constants;
25
import org.apache.fop.fo.Constants;
26
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
26
import org.apache.fop.layoutmgr.Keep;
27
import org.apache.fop.layoutmgr.KeepUtil;
28
import org.apache.fop.layoutmgr.table.TableRowIterator;
27
import org.apache.fop.layoutmgr.table.TableRowIterator;
29
import org.apache.fop.traits.MinOptMax;
28
import org.apache.fop.traits.MinOptMax;
30
import org.apache.fop.util.BreakUtil;
29
import org.apache.fop.util.BreakUtil;
Lines 170-189 Link Here
170
     *
169
     *
171
     * @return the strength of the keep-with-previous constraint
170
     * @return the strength of the keep-with-previous constraint
172
     */
171
     */
173
    public int getKeepWithPreviousStrength() {
172
    public Keep getKeepWithPrevious() {
174
        int strength = BlockLevelLayoutManager.KEEP_AUTO;
173
        Keep keep = Keep.KEEP_AUTO;
175
        TableRow row = getTableRow();
174
        TableRow row = getTableRow();
176
        if (row != null) {
175
        if (row != null) {
177
            strength = Math.max(strength,
176
            keep = Keep.getKeep(row.getKeepWithPrevious());
178
                    KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithPrevious()));
179
        }
177
        }
180
        for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
178
        for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
181
            GridUnit gu = (GridUnit) iter.next();
179
            GridUnit gu = (GridUnit) iter.next();
182
            if (gu.isPrimary()) {
180
            if (gu.isPrimary()) {
183
                strength = Math.max(strength, gu.getPrimary().getKeepWithPreviousStrength());
181
                keep = keep.compare(gu.getPrimary().getKeepWithPrevious());
184
            }
182
            }
185
        }
183
        }
186
        return strength;
184
        return keep;
187
    }
185
    }
188
186
189
    /**
187
    /**
Lines 192-211 Link Here
192
     *
190
     *
193
     * @return the strength of the keep-with-next constraint
191
     * @return the strength of the keep-with-next constraint
194
     */
192
     */
195
    public int getKeepWithNextStrength() {
193
    public Keep getKeepWithNext() {
196
        int strength = BlockLevelLayoutManager.KEEP_AUTO;
194
        Keep keep = Keep.KEEP_AUTO;
197
        TableRow row = getTableRow();
195
        TableRow row = getTableRow();
198
        if (row != null) {
196
        if (row != null) {
199
            strength = Math.max(strength,
197
            keep = Keep.getKeep(row.getKeepWithNext());
200
                    KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithNext()));
201
        }
198
        }
202
        for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
199
        for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
203
            GridUnit gu = (GridUnit) iter.next();
200
            GridUnit gu = (GridUnit) iter.next();
204
            if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) {
201
            if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) {
205
                strength = Math.max(strength, gu.getPrimary().getKeepWithNextStrength());
202
                keep = keep.compare(gu.getPrimary().getKeepWithNext());
206
            }
203
            }
207
        }
204
        }
208
        return strength;
205
        return keep;
209
    }
206
    }
210
207
211
    /**
208
    /**
Lines 213-228 Link Here
213
     * not take the parent table's keeps into account!
210
     * not take the parent table's keeps into account!
214
     * @return the keep-together strength
211
     * @return the keep-together strength
215
     */
212
     */
216
    public int getKeepTogetherStrength() {
213
    public Keep getKeepTogether() {
217
        TableRow row = getTableRow();
214
        TableRow row = getTableRow();
218
        int strength = BlockLevelLayoutManager.KEEP_AUTO;
215
        Keep keep = Keep.KEEP_AUTO;
219
        if (row != null) {
216
        if (row != null) {
220
            strength = Math.max(strength, KeepUtil.getKeepStrength(
217
            keep = Keep.getKeep(row.getKeepTogether());
221
                    row.getKeepTogether().getWithinPage()));
222
            strength = Math.max(strength, KeepUtil.getKeepStrength(
223
                    row.getKeepTogether().getWithinColumn()));
224
        }
218
        }
225
        return strength;
219
        return keep;
226
    }
220
    }
227
221
228
    /**
222
    /**
(-)src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java (-12 / +11 lines)
Lines 19-32 Link Here
19
19
20
package org.apache.fop.fo.flow.table;
20
package org.apache.fop.fo.flow.table;
21
21
22
import java.util.LinkedList;
23
import java.util.List;
22
import java.util.List;
24
23
25
import org.apache.fop.fo.Constants;
24
import org.apache.fop.fo.Constants;
26
import org.apache.fop.fo.FONode;
25
import org.apache.fop.fo.FONode;
27
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
26
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
28
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
29
import org.apache.fop.layoutmgr.ElementListUtils;
27
import org.apache.fop.layoutmgr.ElementListUtils;
28
import org.apache.fop.layoutmgr.Keep;
30
import org.apache.fop.layoutmgr.table.TableCellLayoutManager;
29
import org.apache.fop.layoutmgr.table.TableCellLayoutManager;
31
30
32
/**
31
/**
Lines 54-61 Link Here
54
    private boolean isSeparateBorderModel;
53
    private boolean isSeparateBorderModel;
55
    private int halfBorderSeparationBPD;
54
    private int halfBorderSeparationBPD;
56
55
57
    private int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
56
    private Keep keepWithPrevious = Keep.KEEP_AUTO;
58
    private int keepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
57
    private Keep keepWithNext = Keep.KEEP_AUTO;
59
    private int breakBefore = Constants.EN_AUTO;
58
    private int breakBefore = Constants.EN_AUTO;
60
    private int breakAfter = Constants.EN_AUTO;
59
    private int breakAfter = Constants.EN_AUTO;
61
60
Lines 334-349 Link Here
334
     *
333
     *
335
     * @return the keep-with-previous strength
334
     * @return the keep-with-previous strength
336
     */
335
     */
337
    public int getKeepWithPreviousStrength() {
336
    public Keep getKeepWithPrevious() {
338
        return keepWithPrevious;
337
        return keepWithPrevious;
339
    }
338
    }
340
339
341
    /**
340
    /**
342
     * Don't use, reserved for TableCellLM. TODO
341
     * Don't use, reserved for TableCellLM. TODO
343
     * @param strength the keep strength
342
     * @param keep the keep strength
344
     */
343
     */
345
    public void setKeepWithPreviousStrength(int strength) {
344
    public void setKeepWithPrevious(Keep keep) {
346
        this.keepWithPrevious = strength;
345
        this.keepWithPrevious = keep;
347
    }
346
    }
348
347
349
    /**
348
    /**
Lines 352-367 Link Here
352
     *
351
     *
353
     * @return the keep-with-next strength
352
     * @return the keep-with-next strength
354
     */
353
     */
355
    public int getKeepWithNextStrength() {
354
    public Keep getKeepWithNext() {
356
        return keepWithNext;
355
        return keepWithNext;
357
    }
356
    }
358
357
359
    /**
358
    /**
360
     * Don't use, reserved for TableCellLM. TODO
359
     * Don't use, reserved for TableCellLM. TODO
361
     * @param strength the keep strength
360
     * @param keep the keep strength
362
     */
361
     */
363
    public void setKeepWithNextStrength(int strength) {
362
    public void setKeepWithNext(Keep keep) {
364
        this.keepWithNext = strength;
363
        this.keepWithNext = keep;
365
    }
364
    }
366
365
367
    /**
366
    /**
(-)test/layoutengine/standard-testcases/block_keep_within-column.xml (+140 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
  Licensed to the Apache Software Foundation (ASF) under one or more
4
  contributor license agreements.  See the NOTICE file distributed with
5
  this work for additional information regarding copyright ownership.
6
  The ASF licenses this file to You under the Apache License, Version 2.0
7
  (the "License"); you may not use this file except in compliance with
8
  the License.  You may obtain a copy of the License at
9
10
       http://www.apache.org/licenses/LICENSE-2.0
11
12
  Unless required by applicable law or agreed to in writing, software
13
  distributed under the License is distributed on an "AS IS" BASIS,
14
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
  See the License for the specific language governing permissions and
16
  limitations under the License.
17
-->
18
<!-- $Id$ -->
19
<testcase>
20
  <info>
21
    <p>
22
      This test checks whether keeps within-column are respected.
23
    </p>
24
  </info>
25
  <fo>
26
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
27
      <fo:layout-master-set>
28
        <fo:simple-page-master master-name="page" page-width="400pt" page-height="70pt">
29
          <fo:region-body column-count="5" />
30
        </fo:simple-page-master>
31
      </fo:layout-master-set>
32
      <fo:page-sequence master-reference="page" font-size="10pt">
33
        <fo:flow flow-name="xsl-region-body">
34
          <fo:block break-before="page">
35
            <!-- simple test: keep the second block together within
36
                 one column, breaking the preceding block early 
37
                 if necessary -->
38
            <fo:block id="block-1">
39
              [BOB-1] foo bar foo bar foo bar foo bar foo bar
40
              foo bar foo bar foo bar foo bar foo bar foo bar
41
              foo bar foo bar foo bar foo bar foo bar foo bar
42
              foo bar foo bar foo bar foo bar foo bar [EOB-1]
43
            </fo:block>
44
            <fo:block id="block-2" keep-together.within-column="always">
45
              [BOB-2] foo bar foo bar foo bar foo bar foo [EOB-2]
46
            </fo:block>
47
          </fo:block>
48
          <fo:block break-before="page">
49
            <!-- same as the first, but now a nested block
50
                 with a higher integer value, and some content
51
                 following -->
52
            <fo:block id="block-3" keep-together.within-column="5">
53
              [BOB-3] foo bar foo bar foo bar foo bar foo bar
54
              foo bar foo bar foo bar foo bar foo bar foo bar
55
              foo bar foo bar foo bar foo bar foo bar foo bar
56
              foo bar foo bar foo bar foo bar foo bar foo bar
57
              foo bar foo bar foo bar foo bar foo bar foo bar
58
              <fo:block font-weight="bold" id="block-3a" keep-together.within-column="always">
59
                [BOB-3a] foo bar foo bar foo bar foo bar foo [EOB-3a]
60
              </fo:block>
61
              foo bar foo bar foo bar foo bar foo bar foo bar
62
              foo bar foo bar foo bar foo bar foo bar foo bar
63
              foo bar foo bar foo bar foo bar foo bar [EOB-3]
64
            </fo:block>
65
          </fo:block>
66
          <fo:block break-before="page">
67
            <!-- nested block must be kept together within the same
68
                 page, while the outer block may be broken, if necessary -->
69
            <fo:block font-style="italic" id="block-4" keep-together.within-column="5">
70
              [BOB-4] foo bar foo bar foo bar foo bar foo bar
71
              foo bar foo bar foo bar foo bar foo bar foo bar
72
              foo bar foo bar foo bar foo bar foo bar foo bar
73
              foo bar foo bar foo bar foo bar foo bar foo bar
74
              foo bar foo bar foo bar foo bar foo bar foo bar
75
              foo bar foo bar foo bar foo bar foo bar foo bar
76
              <fo:block id="block-4a" keep-together.within-page="always">
77
                [BOB-4a] foo bar foo bar foo bar foo bar foo bar
78
                foo bar foo bar foo bar foo bar foo bar foo bar
79
                foo bar foo bar foo bar foo bar foo bar foo bar
80
                foo bar foo bar foo bar foo bar foo bar foo bar
81
                foo bar foo bar foo bar foo bar foo bar foo bar
82
                foo bar foo bar foo bar foo bar foo bar foo bar
83
                foo bar foo bar foo bar foo bar foo bar foo bar
84
                foo bar foo bar foo bar foo bar foo bar [EOB-4a]
85
              </fo:block>
86
              foo bar foo bar foo bar foo bar foo bar foo bar
87
              foo bar foo bar foo bar foo bar foo bar foo bar
88
              foo bar foo bar foo bar foo bar foo bar [EOB-4]
89
            </fo:block>
90
          </fo:block>
91
          <fo:block break-before="page">
92
            <!-- test keep-with-next in conjunction with keep-together
93
                 respecting the default value for widows/orphans -->
94
            <fo:block id="block-5">
95
              <fo:block id="block-5a">
96
              [BOB-5a] foo bar foo bar foo bar foo bar foo bar
97
              foo bar foo bar foo bar foo bar foo bar foo bar
98
              foo bar foo bar foo bar foo bar foo bar foo bar
99
              foo bar foo bar foo bar foo bar foo bar foo bar
100
              foo bar foo bar foo bar foo bar foo bar foo bar
101
              foo bar foo bar foo bar foo bar foo bar [EOB-5a]
102
              </fo:block>
103
              <fo:block id="block-5b" keep-with-next.within-column="always">
104
              [BOB-5b] foo bar foo bar foo bar foo bar foo bar
105
              foo bar foo bar foo bar foo bar foo bar [EOB-5b]
106
              </fo:block>
107
              <fo:block id="block-5c" keep-together.within-column="always">
108
              [BOB-5c] foo bar foo bar foo bar foo bar foo bar
109
              foo bar foo bar foo bar foo bar foo bar [EOB-5c]
110
              </fo:block>
111
            </fo:block>
112
          </fo:block>
113
          <fo:block break-before="page">
114
            <!-- test keep-together in conjunction with keep-with-previous -->
115
            <fo:block id="block-6">
116
              <fo:block id="block-6a">
117
              [BOB-6a] foo bar foo bar foo bar foo bar foo bar
118
              foo bar foo bar foo bar foo bar foo bar foo bar
119
              foo bar foo bar foo bar foo bar foo bar foo bar
120
              foo bar foo bar foo bar foo bar foo bar foo bar
121
              foo bar foo bar foo bar foo bar foo bar [EOB-6a]
122
              </fo:block>
123
              <fo:block id="block-6b" keep-together.within-column="always">
124
              [BOB-6b] foo bar foo bar foo bar foo bar foo bar [EOB-6b]
125
              </fo:block>
126
              <fo:block id="block-6c" keep-with-previous.within-column="always">
127
              [BOB-6c] foo bar foo bar foo bar foo bar foo bar
128
              foo bar foo bar foo bar foo bar foo bar [EOB-6c]
129
              </fo:block>
130
            </fo:block>
131
          </fo:block>
132
        </fo:flow>
133
      </fo:page-sequence>
134
    </fo:root>
135
  </fo>
136
  <checks>
137
    <eval expected="10" xpath="count(//page)" />
138
  </checks>
139
</testcase>
140
(-)test/layoutengine/standard-testcases/inline_block_nested_6.xml (-4 / +3 lines)
Lines 52-67 Link Here
52
      <skip>5</skip>
52
      <skip>5</skip>
53
      <!-- penalty between blocks b11 and b12, set by InlineLM in b1 -->
53
      <!-- penalty between blocks b11 and b12, set by InlineLM in b1 -->
54
      <penalty w="0" p="0"/>
54
      <penalty w="0" p="0"/>
55
      <skip>6</skip>
55
      <skip>5</skip>
56
      <!-- penalty between blocks b21 and b22, set by InlineLM in b2 -->
56
      <!-- penalty between blocks b21 and b22, set by InlineLM in b2 -->
57
      <!-- keep-together.within-page="always" -->
57
      <!-- keep-together.within-page="always" -->
58
      <penalty w="0" p="1000"/>
58
      <penalty w="0" p="1000"/>
59
      <skip>6</skip>
59
      <skip>3</skip>
60
      <!-- penalty between blocks b31 and b32, set by InlineLM in b3 -->
60
      <!-- penalty between blocks b31 and b32, set by InlineLM in b3 -->
61
      <!-- keep-with-next.within-page="always" -->
61
      <!-- keep-with-next.within-page="always" -->
62
      <penalty w="0" p="1000"/>
62
      <penalty w="0" p="1000"/>
63
      <skip>5</skip>
63
      <skip>14</skip>
64
      <skip>3</skip>
65
    </element-list>
64
    </element-list>
66
  </checks>
65
  </checks>
67
</testcase>			          
66
</testcase>			          
(-)test/layoutengine/standard-testcases/table-row_keep-together.xml (-3 / +3 lines)
Lines 64-73 Link Here
64
    <element-list category="breaker" index="0">
64
    <element-list category="breaker" index="0">
65
      <box w="14400"/>
65
      <box w="14400"/>
66
      <penalty w="0" p="0"/>
66
      <penalty w="0" p="0"/>
67
      <box w="28800"/>
68
      <penalty w="0" p="0"/>
69
      <box w="14400"/>
67
      <box w="14400"/>
70
      <skip>3</skip>
68
      <penalty w="0" p="INF"/>
69
      <box w="14400"/>
70
      <skip>5</skip>
71
    </element-list>
71
    </element-list>
72
  </checks>
72
  </checks>
73
</testcase>
73
</testcase>
(-)test/layoutengine/standard-testcases/table_keep-together.xml (-1 / +3 lines)
Lines 101-109 Link Here
101
    <element-list category="breaker" index="0">
101
    <element-list category="breaker" index="0">
102
      <box w="14400"/>
102
      <box w="14400"/>
103
      <penalty w="0" p="0"/>
103
      <penalty w="0" p="0"/>
104
      <box w="28800"/>
104
      <box w="14400"/>
105
      <penalty w="0" p="INF"/>
105
      <penalty w="0" p="INF"/>
106
      <box w="14400"/>
106
      <box w="14400"/>
107
      <penalty w="0" p="INF"/>
108
      <box w="14400"/>
107
      <penalty w="0" p="0"/>
109
      <penalty w="0" p="0"/>
108
      <box w="14400"/>
110
      <box w="14400"/>
109
      <skip>3</skip>
111
      <skip>3</skip>

Return to bug 46905