Index: src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java (working copy) @@ -415,18 +415,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - return KEEP_AUTO; + public Keep getKeepTogether() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; } } Index: src/java/org/apache/fop/layoutmgr/KeepUtil.java =================================================================== --- src/java/org/apache/fop/layoutmgr/KeepUtil.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/KeepUtil.java (working copy) @@ -1,109 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.layoutmgr; - -import org.apache.fop.fo.Constants; -import org.apache.fop.fo.properties.KeepProperty; -import org.apache.fop.fo.properties.Property; - -/** - * Utility class for working with keeps. - */ -public class KeepUtil { - - /** - * Converts a keep property into an integer value. - *

- * Note: The conversion restricts the effectively available integer range by two values. - * Integer.MIN_VALUE is used to represent the value "auto" and - * Integer.MAX_VALUE is used to represebt the value "always". - * @param keep the keep property - * @return the keep value as an integer - */ - public static int getKeepStrength(Property keep) { - if (keep.isAuto()) { - return BlockLevelLayoutManager.KEEP_AUTO; - } else if (keep.getEnum() == Constants.EN_ALWAYS) { - return BlockLevelLayoutManager.KEEP_ALWAYS; - } else { - return keep.getNumber().intValue(); - } - } - - /** - * Returns the combined block-level keep strength from a keep property. - *

- * Note: This is a temporary method to be used until it is possible to differentiate between - * page and column keeps! - * @param keep the keep property - * @return the combined keep strength - */ - public static int getCombinedBlockLevelKeepStrength(KeepProperty keep) { - return Math.max( - getKeepStrength(keep.getWithinPage()), - getKeepStrength(keep.getWithinColumn())); - } - - /** - * Indicates whether a keep strength indicates a keep constraint. - * @param strength the keep strength - * @return true if the keep is not "auto" - */ - public static boolean hasKeep(int strength) { - return strength > BlockLevelLayoutManager.KEEP_AUTO; - } - - /** - * Returns the penalty value to be used for a certain keep strength. - *

- * @param keepStrength the keep strength - * @return the penalty value - */ - public static int getPenaltyForKeep(int keepStrength) { - if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) { - return 0; - } - int penalty = KnuthElement.INFINITE; - if (keepStrength < BlockLevelLayoutManager.KEEP_ALWAYS) { - penalty--; - } - return penalty; - } - - /** - * Returns a string representation of a keep strength value. - * @param keepStrength the keep strength - * @return the string representation - */ - public static String keepStrengthToString(int keepStrength) { - if (keepStrength == BlockLevelLayoutManager.KEEP_AUTO) { - return "auto"; - } else if (keepStrength == BlockLevelLayoutManager.KEEP_ALWAYS) { - return "always"; - } else { - return Integer.toString(keepStrength); - } - } - -} Index: src/java/org/apache/fop/layoutmgr/KnuthPenalty.java =================================================================== --- src/java/org/apache/fop/layoutmgr/KnuthPenalty.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/KnuthPenalty.java (working copy) @@ -45,7 +45,7 @@ public static final int FLAGGED_PENALTY = 50; private int penalty; - private boolean bFlagged; + private boolean isFlagged; private int breakClass = -1; /** @@ -55,12 +55,12 @@ * @param p the penalty value of this penalty * @param f is this penalty flagged? * @param pos the Position stored in this penalty - * @param bAux is this penalty auxiliary? + * @param isAuxiliary is this penalty auxiliary? */ - public KnuthPenalty(int w, int p, boolean f, Position pos, boolean bAux) { - super(w, pos, bAux); + public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) { + super(w, pos, isAuxiliary); penalty = p; - bFlagged = f; + isFlagged = f; } /** @@ -69,20 +69,39 @@ * @param w the width of this penalty * @param p the penalty value of this penalty * @param f is this penalty flagged? - * @param iBreakClass the break class of this penalty (one of + * @param breakClass the break class of this penalty (one of * {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE}, * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}) * @param pos the Position stored in this penalty - * @param bAux is this penalty auxiliary? + * @param isAuxiliary is this penalty auxiliary? */ public KnuthPenalty(int w, int p, boolean f, - int iBreakClass, Position pos, boolean bAux) { - super(w, pos, bAux); - penalty = p; - bFlagged = f; - breakClass = iBreakClass; + int breakClass, Position pos, boolean isAuxiliary) { + this(w, p, f, pos, isAuxiliary); + this.breakClass = breakClass; } + private static String getBreakClassName(int breakClass) { + return AbstractBreaker.getBreakClassName(breakClass); + } + + /** + * Get the penalty's value as a {@code java.lang.String}. + * (Mainly used in {@code toString()} methods, to improve readability + * of the trace logs.) + * + * @param penaltyValue the penalty value + * @return the penalty value as a {@code java.lang.String} + */ + protected static String valueOf(int penaltyValue) { + String result = (penaltyValue < 0) ? "-" : ""; + int tmpValue = Math.abs(penaltyValue); + result += (tmpValue == KnuthElement.INFINITE) + ? "INFINITE" + : String.valueOf(tmpValue); + return result; + } + /** {@inheritDoc} */ public boolean isPenalty() { return true; @@ -105,7 +124,7 @@ /** @return true is this penalty is a flagged one. */ public boolean isFlagged() { - return bFlagged; + return isFlagged; } /** {@inheritDoc} */ @@ -121,14 +140,6 @@ return breakClass; } - /** - * Sets the break class for this penalty. - * @param cl the break class (EN_AUTO, EN_COLUMN, EN_PAGE, EN_EVEN_PAGE, EN_ODD_PAGE) - */ - public void setBreakClass(int cl) { - this.breakClass = cl; - } - /** {@inheritDoc} */ public String toString() { StringBuffer sb = new StringBuffer(64); @@ -137,39 +148,22 @@ } sb.append("penalty"); sb.append(" p="); - if (getP() < 0) { - sb.append("-"); - } - if (Math.abs(getP()) == INFINITE) { - sb.append("INFINITE"); - } else { - sb.append(getP()); - } - if (isFlagged()) { + sb.append(valueOf(this.penalty)); + if (this.isFlagged) { sb.append(" [flagged]"); } sb.append(" w="); sb.append(getW()); if (isForcedBreak()) { - sb.append(" (forced break"); - switch (getBreakClass()) { - case Constants.EN_PAGE: - sb.append(", page"); - break; - case Constants.EN_COLUMN: - sb.append(", column"); - break; - case Constants.EN_EVEN_PAGE: - sb.append(", even page"); - break; - case Constants.EN_ODD_PAGE: - sb.append(", odd page"); - break; - default: - } - sb.append(")"); + sb.append(" (forced break, ") + .append(getBreakClassName(this.breakClass)) + .append(")"); + } else if (this.penalty >= 0 && this.breakClass != -1) { + //penalty corresponding to a keep constraint + sb.append(" (keep constraint, ") + .append(getBreakClassName(this.breakClass)) + .append(")"); } return sb.toString(); } - } Index: src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (working copy) @@ -36,32 +36,13 @@ import org.apache.fop.fo.Constants; import org.apache.fop.fo.flow.Block; import org.apache.fop.fo.properties.CommonHyphenation; +import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontTriplet; import org.apache.fop.hyphenation.Hyphenation; import org.apache.fop.hyphenation.Hyphenator; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; -import org.apache.fop.layoutmgr.BreakElement; -import org.apache.fop.layoutmgr.BreakingAlgorithm; -import org.apache.fop.layoutmgr.ElementListObserver; -import org.apache.fop.layoutmgr.InlineKnuthSequence; -import org.apache.fop.layoutmgr.KeepUtil; -import org.apache.fop.layoutmgr.KnuthBlockBox; -import org.apache.fop.layoutmgr.KnuthBox; -import org.apache.fop.layoutmgr.KnuthElement; -import org.apache.fop.layoutmgr.KnuthGlue; -import org.apache.fop.layoutmgr.KnuthPenalty; -import org.apache.fop.layoutmgr.KnuthPossPosIter; -import org.apache.fop.layoutmgr.KnuthSequence; -import org.apache.fop.layoutmgr.LayoutContext; -import org.apache.fop.layoutmgr.LayoutManager; -import org.apache.fop.layoutmgr.LeafPosition; -import org.apache.fop.layoutmgr.ListElement; -import org.apache.fop.layoutmgr.NonLeafPosition; -import org.apache.fop.layoutmgr.Position; -import org.apache.fop.layoutmgr.PositionIterator; -import org.apache.fop.layoutmgr.SpaceSpecifier; +import org.apache.fop.layoutmgr.*; import org.apache.fop.traits.MinOptMax; /** @@ -169,7 +150,6 @@ private AlignmentContext alignmentContext = null; private List knuthParagraphs = null; - private int iReturnedLBP = 0; // parameters of Knuth's algorithm: // penalty value for flagged penalties @@ -605,34 +585,6 @@ //PHASE 2: Create line breaks return createLineBreaks(context.getBPAlignment(), context); - /* - LineBreakPosition lbp = null; - if (breakpoints == null) { - // find the optimal line breaking points for each paragraph - breakpoints = new ArrayList(); - ListIterator paragraphsIterator - = knuthParagraphs.listIterator(knuthParagraphs.size()); - Paragraph currPar = null; - while (paragraphsIterator.hasPrevious()) { - currPar = (Paragraph) paragraphsIterator.previous(); - findBreakingPoints(currPar, context.getStackLimit().opt); - } - }*/ - - //PHASE 3: Return lines - - /* - // get a break point from the list - lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++); - if (iReturnedLBP == breakpoints.size()) { - setFinished(true); - } - - BreakPoss curLineBP = new BreakPoss(lbp); - curLineBP.setFlag(BreakPoss.ISLAST, isFinished()); - curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight)); - return curLineBP; - */ } /** @@ -767,134 +719,6 @@ } /** - * Find a set of breaking points. - * This method is called only once by getNextBreakPoss, and it - * subsequently calls the other findBreakingPoints() method with - * different parameters, until a set of breaking points is found. - * - * @param par the list of elements that must be parted - * into lines - * @param lineWidth the desired length ot the lines - */ - /* - private void findBreakingPoints(Paragraph par, int lineWidth) { - // maximum adjustment ratio permitted - float maxAdjustment = 1; - - // first try - if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) { - // the first try failed, now try something different - log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment); - if (hyphenationProperties.hyphenate == Constants.EN_TRUE) { - // consider every hyphenation point as a legal break - findHyphenationPoints(par); - } else { - // try with a higher threshold - maxAdjustment = 5; - } - - if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) { - // the second try failed too, try with a huge threshold; - // if this fails too, use a different algorithm - log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment - + (hyphenationProperties.hyphenate == Constants.EN_TRUE ? " and hyphenation" : "")); - maxAdjustment = 20; - if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) { - log.debug("No set of breaking points found, using first-fit algorithm"); - } - } - } - } - - private boolean findBreakingPoints(Paragraph par, int lineWidth, - double threshold, boolean force) { - KnuthParagraph knuthPara = new KnuthParagraph(par); - int lines = knuthPara.findBreakPoints(lineWidth, threshold, force); - if (lines == 0) { - return false; - } - - for (int i = lines-1; i >= 0; i--) { - int line = i+1; - if (log.isTraceEnabled()) { - log.trace("Making line from " + knuthPara.getStart(i) + " to " + - knuthPara.getEnd(i)); - } - // compute indent and adjustment ratio, according to - // the value of text-align and text-align-last - - int difference = knuthPara.getDifference(i); - if (line == lines) { - difference += par.lineFillerWidth; - } - int textAlign = (line < lines) - ? textAlignment : textAlignmentLast; - int indent = (textAlign == EN_CENTER) - ? difference / 2 - : (textAlign == EN_END) ? difference : 0; - indent += (line == 1 && knuthParagraphs.indexOf(par) == 0) - ? textIndent.getValue(this) : 0; - double ratio = (textAlign == EN_JUSTIFY) - ? knuthPara.getAdjustRatio(i) : 0; - - int start = knuthPara.getStart(i); - int end = knuthPara.getEnd(i); - makeLineBreakPosition(par, start, end, 0, ratio, indent); - } - return true; - } - - private void makeLineBreakPosition(Paragraph par, - int firstElementIndex, int lastElementIndex, - int insertIndex, double ratio, int indent) { - // line height calculation - - int halfLeading = (lineHeight - lead - follow) / 2; - // height above the main baseline - int lineLead = lead + halfLeading; - // maximum size of top and bottom alignment - int lineFollow = follow + halfLeading; - - ListIterator inlineIterator - = par.listIterator(firstElementIndex); - for (int j = firstElementIndex; - j <= lastElementIndex; - j++) { - KnuthElement element = (KnuthElement) inlineIterator.next(); - if (element.isBox()) { - KnuthInlineBox box = (KnuthInlineBox)element; - if (box.getLead() > lineLead) { - lineLead = box.getLead(); - } - if (box.getTotal() > lineFollow) { - lineFollow = box.getTotal(); - } - if (box.getMiddle() > lineLead + middleShift) { - lineLead += box.getMiddle() - - lineLead - middleShift; - } - if (box.getMiddle() > middlefollow - middleShift) { - middlefollow += box.getMiddle() - - middlefollow + middleShift; - } - } - } - - if (lineFollow - lineLead > middlefollow) { - middlefollow = lineFollow - lineLead; - } - - breakpoints.add(insertIndex, - new LineBreakPosition(this, - knuthParagraphs.indexOf(par), - lastElementIndex , - ratio, 0, indent, - lineLead + middlefollow, - lineLead)); - }*/ - - - /** * Phase 2 of Knuth algorithm: find optimal break points. * @param alignment alignment in BP direction of the paragraph * @param context the layout context @@ -1054,12 +878,12 @@ for (int p = 0; p < knuthParagraphs.size(); p++) { // penalty between paragraphs if (p > 0) { - int strength = getKeepTogetherStrength(); - int penalty = KeepUtil.getPenaltyForKeep(strength); - if (penalty < KnuthElement.INFINITE) { - returnList.add(new BreakElement( - new Position(this), penalty, context)); - } + Keep keep = getKeepTogether(); + returnList.add(new BreakElement( + new Position(this), + keep.getPenalty(), + keep.getContext(), + context)); } LineLayoutPossibilities llPoss; @@ -1098,12 +922,12 @@ && i >= fobj.getOrphans() && i <= llPoss.getChosenLineCount() - fobj.getWidows()) { // penalty allowing a page break between lines - int strength = getKeepTogetherStrength(); - int penalty = KeepUtil.getPenaltyForKeep(strength); - if (penalty < KnuthElement.INFINITE) { - returnList.add(new BreakElement( - returnPosition, penalty, context)); - } + Keep keep = getKeepTogether(); + returnList.add(new BreakElement( + new Position(this), + keep.getPenalty(), + keep.getContext(), + context)); } int endIndex = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); @@ -1283,28 +1107,43 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - return ((BlockLevelLayoutManager) getParent()).getKeepTogetherStrength(); + public KeepProperty getKeepTogetherProperty() { + return ((BlockLevelLayoutManager) getParent()).getKeepTogetherProperty(); } /** {@inheritDoc} */ + public KeepProperty getKeepWithPreviousProperty() { + return ((BlockLevelLayoutManager) getParent()).getKeepWithPreviousProperty(); + } + + /** {@inheritDoc} */ + public KeepProperty getKeepWithNextProperty() { + return ((BlockLevelLayoutManager) getParent()).getKeepWithNextProperty(); + } + + /** {@inheritDoc} */ + public Keep getKeepTogether() { + return ((BlockLevelLayoutManager) getParent()).getKeepTogether(); + } + + /** {@inheritDoc} */ public boolean mustKeepWithPrevious() { - return getKeepWithPreviousStrength() > KEEP_AUTO; + return !getKeepWithPrevious().isAuto(); } /** {@inheritDoc} */ public boolean mustKeepWithNext() { - return getKeepWithNextStrength() > KEEP_AUTO; + return !getKeepWithNext().isAuto(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ @@ -1409,6 +1248,7 @@ break; } //TODO Something's not right here. See block_hyphenation_linefeed_preserve.xml + //for more info: see also https://issues.apache.org/bugzilla/show_bug.cgi?id=38264 // collect word fragments, ignoring auxiliary elements; // each word fragment was created by a different TextLM Index: src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java (working copy) @@ -19,6 +19,8 @@ package org.apache.fop.layoutmgr; +import org.apache.fop.fo.properties.KeepProperty; + /** * The interface for LayoutManagers which generate block areas */ @@ -35,11 +37,6 @@ /** Adjustment class: adjustment for line height */ int LINE_HEIGHT_ADJUSTMENT = 3; - /** The integer value for "auto" keep strength */ - int KEEP_AUTO = Integer.MIN_VALUE; - /** The integer value for "always" keep strength */ - int KEEP_ALWAYS = Integer.MAX_VALUE; - int negotiateBPDAdjustment(int adj, KnuthElement lastElement); void discardSpace(KnuthGlue spaceGlue); @@ -48,7 +45,7 @@ * Returns the keep-together strength for this element. * @return the keep-together strength */ - int getKeepTogetherStrength(); + Keep getKeepTogether(); /** * @return true if this element must be kept together @@ -59,7 +56,7 @@ * Returns the keep-with-previous strength for this element. * @return the keep-with-previous strength */ - int getKeepWithPreviousStrength(); + Keep getKeepWithPrevious(); /** * @return true if this element must be kept with the previous element. @@ -70,11 +67,31 @@ * Returns the keep-with-next strength for this element. * @return the keep-with-next strength */ - int getKeepWithNextStrength(); + Keep getKeepWithNext(); /** * @return true if this element must be kept with the next element. */ boolean mustKeepWithNext(); + /** + * Returns the keep-together property specified on the FObj. + * (optional operation) + * @return the keep-together property + */ + KeepProperty getKeepTogetherProperty(); + + /** + * Returns the keep-with-previous property specified on the FObj. + * (optional operation) + * @return the keep-together property + */ + KeepProperty getKeepWithPreviousProperty(); + + /** + * Returns the keep-with-next property specified on the FObj. + * (optional operation) + * @return the keep-together property + */ + KeepProperty getKeepWithNextProperty(); } Index: src/java/org/apache/fop/layoutmgr/LayoutContext.java =================================================================== --- src/java/org/apache/fop/layoutmgr/LayoutContext.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/LayoutContext.java (working copy) @@ -145,8 +145,8 @@ private int breakBefore; private int breakAfter; - private int pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO; - private int pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO; + private Keep pendingKeepWithNext = Keep.KEEP_AUTO; + private Keep pendingKeepWithPrevious = Keep.KEEP_AUTO; private int disableColumnBalancing; @@ -237,7 +237,7 @@ * Returns the strength of a keep-with-next currently pending. * @return the keep-with-next strength */ - public int getKeepWithNextPending() { + public Keep getKeepWithNextPending() { return this.pendingKeepWithNext; } @@ -245,7 +245,7 @@ * Returns the strength of a keep-with-previous currently pending. * @return the keep-with-previous strength */ - public int getKeepWithPreviousPending() { + public Keep getKeepWithPreviousPending() { return this.pendingKeepWithPrevious; } @@ -253,14 +253,14 @@ * Clears any pending keep-with-next strength. */ public void clearKeepWithNextPending() { - this.pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO; + this.pendingKeepWithNext = Keep.KEEP_AUTO; } /** * Clears any pending keep-with-previous strength. */ public void clearKeepWithPreviousPending() { - this.pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO; + this.pendingKeepWithPrevious = Keep.KEEP_AUTO; } /** @@ -273,18 +273,18 @@ /** * Updates the currently pending keep-with-next strength. - * @param strength the new strength to consider + * @param keep the new strength to consider */ - public void updateKeepWithNextPending(int strength) { - this.pendingKeepWithNext = Math.max(this.pendingKeepWithNext, strength); + public void updateKeepWithNextPending(Keep keep) { + this.pendingKeepWithNext = this.pendingKeepWithNext.compare(keep); } /** * Updates the currently pending keep-with-previous strength. - * @param strength the new strength to consider + * @param keep the new strength to consider */ - public void updateKeepWithPreviousPending(int strength) { - this.pendingKeepWithPrevious = Math.max(this.pendingKeepWithPrevious, strength); + public void updateKeepWithPreviousPending(Keep keep) { + this.pendingKeepWithPrevious = this.pendingKeepWithPrevious.compare(keep); } /** @@ -292,7 +292,7 @@ * @return true if a keep-with-next constraint is pending */ public boolean isKeepWithNextPending() { - return getKeepWithNextPending() != BlockLevelLayoutManager.KEEP_AUTO; + return !getKeepWithNextPending().isAuto(); } /** @@ -300,7 +300,7 @@ * @return true if a keep-with-previous constraint is pending */ public boolean isKeepWithPreviousPending() { - return getKeepWithPreviousPending() != BlockLevelLayoutManager.KEEP_AUTO; + return !getKeepWithPreviousPending().isAuto(); } public void setLeadingSpace(SpaceSpecifier space) { @@ -677,9 +677,8 @@ + "\nStarts New Area: \t" + startsNewArea() + "\nIs Last Area: \t" + isLastArea() + "\nTry Hyphenate: \t" + tryHyphenate() - + "\nKeeps: \t[keep-with-next=" + KeepUtil.keepStrengthToString(getKeepWithNextPending()) - + "][keep-with-previous=" - + KeepUtil.keepStrengthToString(getKeepWithPreviousPending()) + "] pending" + + "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending() + + "][keep-with-previous=" + getKeepWithPreviousPending() + "] pending" + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "][" + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]"; } Index: src/java/org/apache/fop/layoutmgr/Keep.java =================================================================== --- src/java/org/apache/fop/layoutmgr/Keep.java (revision 0) +++ src/java/org/apache/fop/layoutmgr/Keep.java (revision 0) @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.layoutmgr; + +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.properties.KeepProperty; +import org.apache.fop.fo.properties.Property; + +/** + * Object representing a keep constraint, corresponding + * to the XSL-FO keep properties. + */ +public class Keep { + + /** The integer value for "auto" keep strength. */ + private static final int STRENGTH_AUTO = Integer.MIN_VALUE; + + /** The integer value for "always" keep strength. */ + private static final int STRENGTH_ALWAYS = Integer.MAX_VALUE; + + public static final Keep KEEP_AUTO = new Keep(STRENGTH_AUTO, Constants.EN_AUTO); + + public static final Keep KEEP_ALWAYS = new Keep(STRENGTH_ALWAYS, Constants.EN_LINE); + + private int strength; + + private int context; + + private Keep(int strength, int context) { + this.strength = strength; + this.context = context; + } + + private static int getKeepStrength(Property keep) { + if (keep.isAuto()) { + return STRENGTH_AUTO; + } else if (keep.getEnum() == Constants.EN_ALWAYS) { + return STRENGTH_ALWAYS; + } else { + return keep.getNumber().intValue(); + } + } + + /** + * Obtain a Keep instance corresponding to the given {@link KeepProperty} + * + * @param keepProperty the {@link KeepProperty} + * @return a new instance corresponding to the given property + */ + public static Keep getKeep(KeepProperty keepProperty) { + Keep keep = new Keep(STRENGTH_AUTO, Constants.EN_AUTO); + keep.update(keepProperty.getWithinPage(), Constants.EN_PAGE); + keep.update(keepProperty.getWithinColumn(), Constants.EN_COLUMN); + keep.update(keepProperty.getWithinLine(), Constants.EN_LINE); + return keep; + } + + private void update(Property keep, int context) { + if (!keep.isAuto()) { + this.strength = getKeepStrength(keep); + this.context = context; + } + } + + /** @return {@code true} if the keep property was specified as "auto" */ + public boolean isAuto() { + return strength == STRENGTH_AUTO; + } + + /** + * Returns the context of this keep. + * + * @return one of {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or + * {@link Constants#EN_PAGE} + */ + public int getContext() { + return context; + } + + /** @return the penalty value corresponding to the strength of this Keep */ + public int getPenalty() { + if (strength == STRENGTH_AUTO) { + return 0; + } else if (strength == STRENGTH_ALWAYS) { + return KnuthElement.INFINITE; + } else { + return KnuthElement.INFINITE - 1; + } + } + + private static int getKeepContextPriority(int context) { + switch (context) { + case Constants.EN_LINE: return 0; + case Constants.EN_COLUMN: return 1; + case Constants.EN_PAGE: return 2; + case Constants.EN_AUTO: return 3; + default: throw new IllegalArgumentException(); + } + } + + /** + * Compare this Keep instance to another one, and return the + * stronger one if the context is the same + * + * @param other the instance to compare to + * @return the winning Keep instance + */ + public Keep compare(Keep other) { + + /* check strength "always" first, regardless of priority */ + if (this.strength == STRENGTH_ALWAYS + && this.strength > other.strength) { + return this; + } else if (other.strength == STRENGTH_ALWAYS + && other.strength > this.strength) { + return other; + } + + int pThis = getKeepContextPriority(this.context); + int pOther = getKeepContextPriority(other.context); + + /* equal priority: strongest wins */ + if (pThis == pOther) { + return (strength >= other.strength) ? this : other; + } + + /* different priority: lowest priority wins */ + return (pThis < pOther) ? this : other; + } + + /** {@inheritDoc} */ + public String toString() { + return (strength == STRENGTH_AUTO) ? "auto" + : (strength == STRENGTH_ALWAYS) ? "always" + : Integer.toString(strength); + } +} Property changes on: src/java/org/apache/fop/layoutmgr/Keep.java ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java (working copy) @@ -37,6 +37,7 @@ import org.apache.fop.datatypes.Length; import org.apache.fop.fo.flow.BlockContainer; import org.apache.fop.fo.properties.CommonAbsolutePosition; +import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.traits.MinOptMax; import org.apache.fop.traits.SpaceVal; import org.apache.fop.util.ListUtil; @@ -261,7 +262,7 @@ if (!firstVisibleMarkServed) { addKnuthElementsForSpaceBefore(returnList, alignment); - context.updateKeepWithPreviousPending(getKeepWithPreviousStrength()); + context.updateKeepWithPreviousPending(getKeepWithPrevious()); } addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); @@ -271,9 +272,9 @@ //Spaces, border and padding to be repeated at each break addPendingMarks(context); - BlockLevelLayoutManager curLM; // currently active LM - BlockLevelLayoutManager prevLM = null; // previously active LM - while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { + LayoutManager curLM; // currently active LM + LayoutManager prevLM = null; // previously active LM + while ((curLM = getChildLM()) != null) { LayoutContext childLC = new LayoutContext(0); childLC.copyPendingMarksFrom(context); // curLM is a ? @@ -323,8 +324,7 @@ //Avoid NoSuchElementException below (happens with empty blocks) continue; } - if (((ListElement) ListUtil.getLast(returnedList)) - .isForcedBreak()) { + if (ElementListUtils.endsWithForcedBreak(returnedList)) { // a descendant of this block has break-after if (curLM.isFinished()) { // there is no other content in this block; @@ -391,7 +391,7 @@ context.clearPendingMarks(); addKnuthElementsForBreakAfter(returnList, context); - context.updateKeepWithNextPending(getKeepWithNextStrength()); + context.updateKeepWithNextPending(getKeepWithNext()); setFinished(true); return returnList; @@ -1011,23 +1011,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KeepUtil.getCombinedBlockLevelKeepStrength( - getBlockContainerFO().getKeepTogether()); - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + public KeepProperty getKeepTogetherProperty() { + return getBlockContainerFO().getKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength( - getBlockContainerFO().getKeepWithNext()); + public KeepProperty getKeepWithPreviousProperty() { + return getBlockContainerFO().getKeepWithPrevious(); } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength( - getBlockContainerFO().getKeepWithPrevious()); + public KeepProperty getKeepWithNextProperty() { + return getBlockContainerFO().getKeepWithNext(); } /** Index: src/java/org/apache/fop/layoutmgr/BreakElement.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BreakElement.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BreakElement.java (working copy) @@ -41,10 +41,25 @@ * @param context the layout context which contains the pending conditional elements */ public BreakElement(Position position, int penaltyValue, LayoutContext context) { - this(position, 0, penaltyValue, -1, context); + this(position, penaltyValue, -1, context); } /** + * Create a new BreakElement for the given {@code position}, {@code penaltyValue} + * and {@code breakClass}. (Used principally to generate break-possibilities in + * ranges of content that must be kept together within the context corresponding + * to the {@code breakClass}; expected to be one of {@link Constants#EN_AUTO}, + * {@link Constants#EN_LINE}, {@link Constants#EN_COLUMN} or {@link Constants#EN_PAGE}) + * @param position the corresponding {@link Position} + * @param penaltyValue the penalty value + * @param breakClass the break class + * @param context the {@link LayoutContext} + */ + public BreakElement(Position position, int penaltyValue, int breakClass, LayoutContext context) { + this(position, 0, penaltyValue, breakClass, context); + } + + /** * Constructor for hard breaks. * * @param position the Position instance needed by the addAreas stage of the LMs. @@ -65,6 +80,10 @@ this.pendingAfterMarks = context.getPendingAfterMarks(); } + private static String getBreakClassName(int breakClass) { + return AbstractBreaker.getBreakClassName(breakClass); + } + /** {@inheritDoc} */ public boolean isConditional() { return false; //Does not really apply here @@ -143,27 +162,17 @@ /** {@inheritDoc} */ public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuffer sb = new StringBuffer(64); sb.append("BreakPossibility[p:"); - sb.append(this.penaltyValue); + sb.append(KnuthPenalty.valueOf(this.penaltyValue)); if (isForcedBreak()) { - sb.append(" (forced break"); - switch (getBreakClass()) { - case Constants.EN_PAGE: - sb.append(", page"); - break; - case Constants.EN_COLUMN: - sb.append(", column"); - break; - case Constants.EN_EVEN_PAGE: - sb.append(", even page"); - break; - case Constants.EN_ODD_PAGE: - sb.append(", odd page"); - break; - default: - } - sb.append(")"); + sb.append(" (forced break, ") + .append(getBreakClassName(this.breakClass)) + .append(")"); + } else if (this.penaltyValue >= 0 && this.breakClass != -1) { + sb.append(" (keep constraint, ") + .append(getBreakClassName(this.breakClass)) + .append(")"); } sb.append("; w:"); sb.append(penaltyWidth); Index: src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java (working copy) @@ -63,10 +63,6 @@ /** {@inheritDoc} */ public List getNextKnuthElements(LayoutContext context, int alignment) { - // set layout dimensions - int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth(); - int flowBPD = getCurrentPV().getBodyRegion().getBPD(); - // currently active LM LayoutManager curLM; List returnedList; @@ -84,12 +80,10 @@ int disableColumnBalancing = EN_FALSE; if (curLM instanceof BlockLayoutManager) { span = ((BlockLayoutManager)curLM).getBlockFO().getSpan(); - disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO() - .getDisableColumnBalancing(); + disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO().getDisableColumnBalancing(); } else if (curLM instanceof BlockContainerLayoutManager) { span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan(); - disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO() - .getDisableColumnBalancing(); + disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO().getDisableColumnBalancing(); } int currentSpan = context.getCurrentSpan(); @@ -113,6 +107,7 @@ // get elements from curLM returnedList = curLM.getNextKnuthElements(childLC, alignment); + //int contentHeight = ElementListUtils.calcContentLength(returnedList); //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size()); if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) { context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); @@ -154,7 +149,7 @@ context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); childLC.clearKeepWithNextPending(); - context.updateKeepWithNextPending(getKeepWithNextStrength()); + context.updateKeepWithNextPending(getKeepWithNext()); } SpaceResolver.resolveElementList(returnList); @@ -203,18 +198,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - return KEEP_AUTO; + public Keep getKeepTogether() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ Index: src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java (working copy) @@ -92,18 +92,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - return getParentKeepTogetherStrength(); + public Keep getKeepTogether() { + return getParentKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; } } Index: src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java (working copy) @@ -210,21 +210,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - KeepProperty keep = getBlockFO().getKeepTogether(); - int strength = KeepUtil.getCombinedBlockLevelKeepStrength(keep); - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + public KeepProperty getKeepTogetherProperty() { + return getBlockFO().getKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithNext()); + public KeepProperty getKeepWithPreviousProperty() { + return getBlockFO().getKeepWithPrevious(); } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithPrevious()); + public KeepProperty getKeepWithNextProperty() { + return getBlockFO().getKeepWithNext(); } /** {@inheritDoc} */ Index: src/java/org/apache/fop/layoutmgr/PageBreaker.java =================================================================== --- src/java/org/apache/fop/layoutmgr/PageBreaker.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/PageBreaker.java (working copy) @@ -443,9 +443,7 @@ pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished(); } - /** - * @return the current child flow layout manager - */ + /** @return the current child flow layout manager */ protected LayoutManager getCurrentChildLM() { return childFLM; } @@ -464,45 +462,52 @@ */ private void handleBreakTrait(int breakVal) { Page curPage = pslm.getCurrentPage(); - if (breakVal == Constants.EN_ALL) { + switch (breakVal) { + case Constants.EN_ALL: //break due to span change in multi-column layout curPage.getPageViewport().createSpan(true); return; - } else if (breakVal == Constants.EN_NONE) { + case Constants.EN_NONE: curPage.getPageViewport().createSpan(false); return; - } else if (breakVal == Constants.EN_COLUMN - || breakVal <= 0 - || breakVal == Constants.EN_AUTO) { + case Constants.EN_COLUMN: + case Constants.EN_AUTO: + case Constants.EN_PAGE: + case -1: PageViewport pv = curPage.getPageViewport(); //Check if previous page was spanned boolean forceNewPageWithSpan = false; RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion( Constants.FO_REGION_BODY); - if (rb.getColumnCount() > 1 - && pv.getCurrentSpan().getColumnCount() == 1) { - forceNewPageWithSpan = true; - } + forceNewPageWithSpan + = (rb.getColumnCount() > 1 + && pv.getCurrentSpan().getColumnCount() == 1); if (forceNewPageWithSpan) { + log.trace("Forcing new page with span"); curPage = pslm.makeNewPage(false, false); curPage.getPageViewport().createSpan(true); } else if (pv.getCurrentSpan().hasMoreFlows()) { + log.trace("Moving to next flow"); pv.getCurrentSpan().moveToNextFlow(); } else { - curPage = pslm.makeNewPage(false, false); + log.trace("Making new page"); + /*curPage = */pslm.makeNewPage(false, false); } return; + default: + log.debug("handling break-before after page " + pslm.getCurrentPageNum() + + " breakVal=" + getBreakClassName(breakVal)); + if (needBlankPageBeforeNew(breakVal)) { + log.trace("Inserting blank page"); + /*curPage = */pslm.makeNewPage(true, false); + } + if (needNewPage(breakVal)) { + log.trace("Making new page"); + /*curPage = */pslm.makeNewPage(false, false); + } } - log.debug("handling break-before after page " + pslm.getCurrentPageNum() - + " breakVal=" + getBreakClassName(breakVal)); - if (needBlankPageBeforeNew(breakVal)) { - curPage = pslm.makeNewPage(true, false); - } - if (needNewPage(breakVal)) { - curPage = pslm.makeNewPage(false, false); - } } /** Index: src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java =================================================================== --- src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java (working copy) @@ -190,6 +190,75 @@ footnoteElementIndex = -1; } + private int currentKeepContext = Constants.EN_AUTO; + private KnuthNode lastBeforeKeepContextSwitch; + + /** + * {@inheritDoc} + * Overridden to defer a part to the next page, if it + * must be kept within one page, but is too large to fit in + * the last column. + */ + protected KnuthNode recoverFromTooLong(KnuthNode lastTooLong) { + + if (log.isDebugEnabled()) { + log.debug("Recovering from too long: " + lastTooLong); + log.debug("\tlastTooShort = " + getLastTooShort()); + log.debug("\tlastBeforeKeepContextSwitch = " + lastBeforeKeepContextSwitch); + log.debug("\tcurrentKeepContext = " + AbstractBreaker.getBreakClassName(currentKeepContext)); + } + + if (lastBeforeKeepContextSwitch == null + || currentKeepContext == Constants.EN_AUTO) { + return super.recoverFromTooLong(lastTooLong); + } + + KnuthNode node = lastBeforeKeepContextSwitch; + lastBeforeKeepContextSwitch = null; + // content would overflow, insert empty page/column(s) and try again + while (!pageProvider.endPage(node.line - 1)) { + log.trace("Adding node for empty column"); + node = createNode( + node.position, + node.line + 1, 1, + 0, 0, 0, + 0, 0, 0, + 0, 0, node); + } + return node; + } + + /** + * Compare two KnuthNodes and return the node with the least demerit. + * + * @param node1 The first knuth node. + * @param node2 The other knuth node. + * @return the node with the least demerit. + */ + protected KnuthNode compareNodes(KnuthNode node1, KnuthNode node2) { + + /* if either node is null, return the other one */ + if (node1 == null || node2 == null) { + return (node1 == null) ? node2 : node1; + } + + /* if either one of the nodes corresponds to a mere column-break, + * and the other one corresponds to a page-break, return the page-break node + */ + if (pageProvider != null) { + if (pageProvider.endPage(node1.line - 1) + && !pageProvider.endPage(node2.line - 1)) { + return node1; + } else if (pageProvider.endPage(node2.line - 1) + && !pageProvider.endPage(node1.line - 1)) { + return node2; + } + } + + /* all other cases: use superclass implementation */ + return super.compareNodes(node1, node2); + } + /** {@inheritDoc} */ protected KnuthNode createNode(int position, int line, int fitness, int totalWidth, int totalStretch, int totalShrink, @@ -234,6 +303,28 @@ } /** + * {@inheritDoc} + * Overridden to consider penalties with value {@link KnuthElement#INFINITE} + * as legal break-points, if the current keep-context allows this + * (a keep-*.within-page="always" constraint still permits column-breaks) + */ + protected void handlePenaltyAt(KnuthPenalty penalty, int position, + int allowedBreaks) { + super.handlePenaltyAt(penalty, position, allowedBreaks); + /* if the penalty had value INFINITE, default implementation + * will not have considered it a legal break, but it could still + * be one. + */ + if (penalty.getP() == KnuthPenalty.INFINITE) { + int breakClass = penalty.getBreakClass(); + if (breakClass == Constants.EN_PAGE + || breakClass == Constants.EN_COLUMN) { + considerLegalBreak(penalty, position); + } + } + } + + /** * Handles the footnotes cited inside a block-level box. Updates footnotesList and the * value of totalFootnotesLength with the lengths of the given footnotes. * @param elementLists list of KnuthElement sequences corresponding to the footnotes @@ -317,10 +408,60 @@ /** {@inheritDoc} */ protected void considerLegalBreak(KnuthElement element, int elementIdx) { + if (element.isPenalty()) { + int breakClass = ((KnuthPenalty) element).getBreakClass(); + switch (breakClass) { + case Constants.EN_PAGE: + case Constants.EN_COLUMN: + if (this.currentKeepContext != breakClass) { + this.lastBeforeKeepContextSwitch = getLastTooShort(); + } + this.currentKeepContext = breakClass; + break; + case Constants.EN_AUTO: + this.currentKeepContext = breakClass; + break; + default: + //nop + } + } super.considerLegalBreak(element, elementIdx); newFootnotes = false; } + /** {@inheritDoc} */ + protected boolean elementCanEndLine(KnuthElement element, int line) { + if (!(element.isPenalty()) || pageProvider == null) { + return true; + } else { + KnuthPenalty p = (KnuthPenalty) element; + if (p.getP() <= 0) { + return true; + } else { + int context = p.getBreakClass(); + switch (context) { + case Constants.EN_LINE: + case Constants.EN_COLUMN: + return p.getP() < KnuthPenalty.INFINITE; + case Constants.EN_PAGE: + return p.getP() < KnuthPenalty.INFINITE + || !pageProvider.endPage(line - 1); + case Constants.EN_AUTO: + log.warn("keep is not auto but context is"); + return true; + default: + if (p.getP() < KnuthPenalty.INFINITE) { + log.warn("Non recognized keep context:" + context); + return true; + } else { + return false; + } + } + } + } + } + + /** {@inheritDoc} */ protected int computeDifference(KnuthNode activeNode, KnuthElement element, int elementIndex) { KnuthPageNode pageNode = (KnuthPageNode) activeNode; Index: src/java/org/apache/fop/layoutmgr/PageProvider.java =================================================================== --- src/java/org/apache/fop/layoutmgr/PageProvider.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/PageProvider.java (working copy) @@ -146,7 +146,50 @@ return this.lastReportedBPD; } + // Wish there were a more elegant way to do this in Java + private int[] getColIndexAndColCount(int index) { + int columnCount = 0; + int colIndex = startColumnOfCurrentElementList + index; + int pageIndex = -1; + do { + colIndex -= columnCount; + pageIndex++; + Page page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); + columnCount = page.getPageViewport().getCurrentSpan().getColumnCount(); + } while (colIndex >= columnCount); + return new int[] {colIndex, columnCount}; + } + /** + * Checks if a break at the passed index would start a new page + * @param index the index of the element before the break + * @return {@code true} if the break starts a new page + */ + boolean startPage(int index) { + return getColIndexAndColCount(index)[0] == 0; + } + + /** + * Checks if a break at the passed index would end a page + * @param index the index of the element before the break + * @return {@code true} if the break ends a page + */ + boolean endPage(int index) { + int[] colIndexAndColCount = getColIndexAndColCount(index); + return colIndexAndColCount[0] == colIndexAndColCount[1] - 1; + } + + /** + * Obtain the applicable column-count for the element at the + * passed index + * @param index the index of the element + * @return the number of columns + */ + int getColumnCount(int index) { + return getColIndexAndColCount(index)[1]; + } + + /** * Returns the part index (0 0) { if (end[0] + 1 == elementLists[0].size()) { - keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnLabel); + keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel); } if (end[1] + 1 == elementLists[1].size()) { - keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnBody); + keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody); } // compute penalty height and box height @@ -339,14 +339,13 @@ } if (addedBoxHeight < totalHeight) { - int strength = BlockLevelLayoutManager.KEEP_AUTO; - strength = Math.max(strength, keepWithNextActive); - strength = Math.max(strength, getKeepTogetherStrength()); + Keep keep = keepWithNextActive.compare(getKeepTogether()); int p = stepPenalty; if (p > -KnuthElement.INFINITE) { - p = Math.max(p, KeepUtil.getPenaltyForKeep(strength)); + p = Math.max(p, keep.getPenalty()); } - returnList.add(new BreakElement(stepPosition, penaltyHeight, p, -1, context)); + returnList.add(new BreakElement(stepPosition, penaltyHeight, p, keep.getContext(), + context)); } } @@ -644,21 +643,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KeepUtil.getCombinedBlockLevelKeepStrength( - getListItemFO().getKeepTogether()); - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + public KeepProperty getKeepTogetherProperty() { + return getListItemFO().getKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithNext()); + public KeepProperty getKeepWithPreviousProperty() { + return getListItemFO().getKeepWithPrevious(); } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getListItemFO().getKeepWithPrevious()); + public KeepProperty getKeepWithNextProperty() { + return getListItemFO().getKeepWithNext(); } /** {@inheritDoc} */ Index: src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (working copy) @@ -28,8 +28,9 @@ import org.apache.fop.fo.flow.AbstractListItemPart; import org.apache.fop.fo.flow.ListItemBody; import org.apache.fop.fo.flow.ListItemLabel; +import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; -import org.apache.fop.layoutmgr.KeepUtil; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.NonLeafPosition; @@ -221,20 +222,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getPartFO().getKeepTogether()); - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + public KeepProperty getKeepTogetherProperty() { + return getPartFO().getKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; } } Index: src/java/org/apache/fop/layoutmgr/table/ActiveCell.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/ActiveCell.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/ActiveCell.java (working copy) @@ -32,8 +32,8 @@ import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.ElementListUtils; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthElement; @@ -75,7 +75,7 @@ /** True if the next CellPart that will be created will be the last one for this cell. */ private boolean lastCellPart; - private int keepWithNextStrength; + private Keep keepWithNext; private int spanIndex = 0; @@ -218,7 +218,7 @@ includedLength = -1; // Avoid troubles with cells having content of zero length totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList); endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1; - keepWithNextStrength = BlockLevelLayoutManager.KEEP_AUTO; + keepWithNext = Keep.KEEP_AUTO; remainingLength = totalLength - previousRowsLength; afterNextStep = new Step(previousRowsLength); @@ -314,7 +314,11 @@ KnuthElement el = (KnuthElement) knuthIter.next(); if (el.isPenalty()) { prevIsBox = false; - if (el.getP() < KnuthElement.INFINITE) { + if (el.getP() < KnuthElement.INFINITE + || ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) { + // TODO too much is being done in that test, only to handle + // keep.within-column properly. + // First legal break point breakFound = true; KnuthPenalty p = (KnuthPenalty) el; @@ -533,7 +537,7 @@ */ CellPart createCellPart() { if (nextStep.end + 1 == elementList.size()) { - keepWithNextStrength = pgu.getKeepWithNextStrength(); + keepWithNext = pgu.getKeepWithNext(); // TODO if keep-with-next is set on the row, must every cell of the row // contribute some content from children blocks? // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/ @@ -576,8 +580,8 @@ } } - int getKeepWithNextStrength() { - return keepWithNextStrength; + Keep getKeepWithNext() { + return keepWithNext; } int getPenaltyValue() { Index: src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (working copy) @@ -35,10 +35,9 @@ import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TablePart; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; -import org.apache.fop.layoutmgr.KeepUtil; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; @@ -213,13 +212,13 @@ context.clearKeepsPending(); context.setBreakBefore(Constants.EN_AUTO); context.setBreakAfter(Constants.EN_AUTO); - int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO; + Keep keepWithPrevious = Keep.KEEP_AUTO; int breakBefore = Constants.EN_AUTO; if (rowGroup != null) { RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper); List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); - keepWithPrevious = Math.max(keepWithPrevious, context.getKeepWithPreviousPending()); + keepWithPrevious = keepWithPrevious.compare(context.getKeepWithPreviousPending()); breakBefore = context.getBreakBefore(); int breakBetween = context.getBreakAfter(); returnList.addAll(nextRowGroupElems); @@ -228,7 +227,7 @@ //Note previous pending keep-with-next and clear the strength //(as the layout context is reused) - int keepWithNextPending = context.getKeepWithNextPending(); + Keep keepWithNextPending = context.getKeepWithNextPending(); context.clearKeepWithNextPending(); //Get elements for next row group @@ -246,17 +245,17 @@ */ //Determine keep constraints - int penaltyStrength = BlockLevelLayoutManager.KEEP_AUTO; - penaltyStrength = Math.max(penaltyStrength, keepWithNextPending); - penaltyStrength = Math.max(penaltyStrength, context.getKeepWithPreviousPending()); + Keep keep = keepWithNextPending.compare(context.getKeepWithPreviousPending()); context.clearKeepWithPreviousPending(); - penaltyStrength = Math.max(penaltyStrength, getTableLM().getKeepTogetherStrength()); - int penaltyValue = KeepUtil.getPenaltyForKeep(penaltyStrength); + keep = keep.compare(getTableLM().getKeepTogether()); + int penaltyValue = keep.getPenalty(); + int breakClass = keep.getContext(); breakBetween = BreakUtil.compareBreakClasses(breakBetween, context.getBreakBefore()); if (breakBetween != Constants.EN_AUTO) { penaltyValue = -KnuthElement.INFINITE; + breakClass = breakBetween; } BreakElement breakElement; ListIterator elemIter = returnList.listIterator(returnList.size()); @@ -267,7 +266,7 @@ breakElement = (BreakElement) elem; } breakElement.setPenaltyValue(penaltyValue); - breakElement.setBreakClass(breakBetween); + breakElement.setBreakClass(breakClass); returnList.addAll(nextRowGroupElems); breakBetween = context.getBreakAfter(); } Index: src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java (working copy) @@ -60,8 +60,8 @@ LinkedList returnList = new LinkedList(); createElementsForRowGroup(context, alignment, bodyType, returnList); - context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPreviousStrength()); - context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNextStrength()); + context.updateKeepWithPreviousPending(rowGroup[0].getKeepWithPrevious()); + context.updateKeepWithNextPending(rowGroup[rowGroup.length - 1].getKeepWithNext()); int breakBefore = Constants.EN_AUTO; TableRow firstRow = rowGroup[0].getTableRow(); Index: src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (working copy) @@ -35,11 +35,11 @@ import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableColumn; +import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.layoutmgr.BlockLevelEventProducer; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ConditionalElementListener; -import org.apache.fop.layoutmgr.KeepUtil; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.LayoutContext; @@ -256,10 +256,10 @@ log.debug(contentKnuthElements); wrapPositionElements(contentKnuthElements, returnList); - context.updateKeepWithPreviousPending(getKeepWithPreviousStrength()); + context.updateKeepWithPreviousPending(getKeepWithPrevious()); context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); - context.updateKeepWithNextPending(getKeepWithNextStrength()); + context.updateKeepWithNextPending(getKeepWithNext()); context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); if (getTable().isSeparateBorderModel()) { @@ -448,20 +448,18 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepTogether()); - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + public KeepProperty getKeepTogetherProperty() { + return getTable().getKeepTogether(); } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithNext()); + public KeepProperty getKeepWithPreviousProperty() { + return getTable().getKeepWithPrevious(); } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KeepUtil.getCombinedBlockLevelKeepStrength(getTable().getKeepWithPrevious()); + public KeepProperty getKeepWithNextProperty() { + return getTable().getKeepWithNext(); } // --------- Property Resolution related functions --------- // Index: src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (working copy) @@ -24,6 +24,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.apache.fop.area.Area; import org.apache.fop.area.Block; import org.apache.fop.area.Trait; @@ -31,25 +32,13 @@ import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; -import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; +import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; -import org.apache.fop.layoutmgr.AreaAdditionUtil; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; -import org.apache.fop.layoutmgr.BlockStackingLayoutManager; -import org.apache.fop.layoutmgr.KeepUtil; -import org.apache.fop.layoutmgr.KnuthBox; -import org.apache.fop.layoutmgr.KnuthElement; -import org.apache.fop.layoutmgr.KnuthGlue; -import org.apache.fop.layoutmgr.KnuthPenalty; -import org.apache.fop.layoutmgr.LayoutContext; -import org.apache.fop.layoutmgr.Position; -import org.apache.fop.layoutmgr.PositionIterator; -import org.apache.fop.layoutmgr.SpaceResolver; -import org.apache.fop.layoutmgr.TraitSetter; +import org.apache.fop.layoutmgr.*; import org.apache.fop.traits.BorderProps; import org.apache.fop.traits.MinOptMax; import org.apache.fop.util.ListUtil; @@ -138,9 +127,9 @@ List contentList = new LinkedList(); List returnList = new LinkedList(); - BlockLevelLayoutManager curLM; // currently active LM - BlockLevelLayoutManager prevLM = null; // previously active LM - while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { + LayoutManager curLM; // currently active LM + LayoutManager prevLM = null; // previously active LM + while ((curLM = getChildLM()) != null) { LayoutContext childLC = new LayoutContext(0); // curLM is a ? childLC.setStackLimitBP(MinOptMax.subtract(context @@ -153,11 +142,12 @@ log.debug("child LM signals pending keep with next"); } if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { - primaryGridUnit.setKeepWithPreviousStrength(childLC.getKeepWithPreviousPending()); + primaryGridUnit.setKeepWithPrevious(childLC.getKeepWithPreviousPending()); childLC.clearKeepWithPreviousPending(); } - if (prevLM != null) { + if (prevLM != null + && !ElementListUtils.endsWithForcedBreak(contentList)) { // there is a block handled by prevLM // before the one handled by curLM addInBetweenBreak(contentList, context, childLC); @@ -174,7 +164,7 @@ } prevLM = curLM; } - primaryGridUnit.setKeepWithNextStrength(context.getKeepWithNextPending()); + primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending()); returnedList = new LinkedList(); if (!contentList.isEmpty()) { @@ -195,7 +185,7 @@ } final KnuthElement lastItem = (KnuthElement) ListUtil .getLast(returnList); - if (((KnuthElement) lastItem).isForcedBreak()) { + if (lastItem.isForcedBreak()) { KnuthPenalty p = (KnuthPenalty) lastItem; primaryGridUnit.setBreakAfter(p.getBreakClass()); p.setP(0); @@ -556,26 +546,23 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KEEP_AUTO; + public Keep getKeepTogether() { + Keep keep = Keep.KEEP_AUTO; if (primaryGridUnit.getRow() != null) { - strength = Math.max(strength, KeepUtil.getKeepStrength( - primaryGridUnit.getRow().getKeepTogether().getWithinPage())); - strength = Math.max(strength, KeepUtil.getKeepStrength( - primaryGridUnit.getRow().getKeepTogether().getWithinColumn())); + keep = Keep.getKeep(primaryGridUnit.getRow().getKeepTogether()); } - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; + keep = keep.compare(getParentKeepTogether()); + return keep; } /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!) + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-next!) } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!) + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; //TODO FIX ME (table-cell has no keep-with-previous!) } // --------- Property Resolution related functions --------- // Index: src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java (working copy) @@ -23,6 +23,7 @@ import org.apache.fop.area.Block; import org.apache.fop.fo.flow.table.TableAndCaption; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.PositionIterator; @@ -201,32 +202,21 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; /* TODO Complete me! - int strength = KeepUtil.getCombinedBlockLevelKeepStrength( - getTableAndCaptionFO().getKeepTogether()); - */ - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; - } - - /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; - /* TODO Complete me! return KeepUtil.getCombinedBlockLevelKeepStrength( getTableAndCaptionFO().getKeepWithNext()); */ } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; /* TODO Complete me! return KeepUtil.getCombinedBlockLevelKeepStrength( getTableAndCaptionFO().getKeepWithPrevious()); */ } -} \ No newline at end of file +} Index: src/java/org/apache/fop/layoutmgr/table/TableStepper.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableStepper.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableStepper.java (working copy) @@ -30,12 +30,10 @@ import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BreakElement; -import org.apache.fop.layoutmgr.KeepUtil; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBox; -import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; @@ -241,40 +239,38 @@ } } - int strength = BlockLevelLayoutManager.KEEP_AUTO; + Keep keep = Keep.KEEP_AUTO; int stepPenalty = 0; for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - strength = Math.max(strength, activeCell.getKeepWithNextStrength()); + keep = keep.compare(activeCell.getKeepWithNext()); stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue()); } if (!rowFinished) { - strength = Math.max(strength, rowGroup[activeRowIndex].getKeepTogetherStrength()); + keep = keep.compare(rowGroup[activeRowIndex].getKeepTogether()); //The above call doesn't take the penalty from the table into account, so... - strength = Math.max(strength, getTableLM().getKeepTogetherStrength()); + keep = keep.compare(getTableLM().getKeepTogether()); } else if (activeRowIndex < rowGroup.length - 1) { - strength = Math.max(strength, - rowGroup[activeRowIndex].getKeepWithNextStrength()); - strength = Math.max(strength, - rowGroup[activeRowIndex + 1].getKeepWithPreviousStrength()); + keep = keep.compare(rowGroup[activeRowIndex].getKeepWithNext()); + keep = keep.compare(rowGroup[activeRowIndex + 1].getKeepWithPrevious()); nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, rowGroup[activeRowIndex].getBreakAfter()); nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, rowGroup[activeRowIndex + 1].getBreakBefore()); } - int p = KeepUtil.getPenaltyForKeep(strength); + int p = keep.getPenalty(); if (rowHeightSmallerThanFirstStep) { rowHeightSmallerThanFirstStep = false; p = KnuthPenalty.INFINITE; } - if (p > -KnuthElement.INFINITE) { - p = Math.max(p, stepPenalty); - } + p = Math.max(p, stepPenalty); + int breakClass = keep.getContext(); if (nextBreakClass != Constants.EN_AUTO) { log.trace("Forced break encountered"); p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0) + breakClass = nextBreakClass; } - returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, nextBreakClass, context)); + returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context)); if (penaltyOrGlueLen < 0) { returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true)); } Index: src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java (working copy) @@ -23,6 +23,7 @@ import org.apache.fop.area.Block; import org.apache.fop.fo.flow.table.TableCaption; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.PositionIterator; @@ -197,30 +198,17 @@ } /** {@inheritDoc} */ - public int getKeepTogetherStrength() { - int strength = KEEP_AUTO; + public Keep getKeepWithNext() { + return Keep.KEEP_AUTO; /* TODO Complete me! - strength = Math.max(strength, KeepUtil.getKeepStrength( - getTableCaptionFO().getKeepTogether().getWithinPage())); - strength = Math.max(strength, KeepUtil.getKeepStrength( - getTableCaptionFO().getKeepTogether().getWithinColumn())); - */ - strength = Math.max(strength, getParentKeepTogetherStrength()); - return strength; - } - - /** {@inheritDoc} */ - public int getKeepWithNextStrength() { - return KEEP_AUTO; - /* TODO Complete me! return KeepUtil.getCombinedBlockLevelKeepStrength( getTableCaptionFO().getKeepWithNext()); */ } /** {@inheritDoc} */ - public int getKeepWithPreviousStrength() { - return KEEP_AUTO; + public Keep getKeepWithPrevious() { + return Keep.KEEP_AUTO; /* TODO Complete me! return KeepUtil.getCombinedBlockLevelKeepStrength( getTableCaptionFO().getKeepWithPrevious()); Index: src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java (working copy) @@ -31,9 +31,11 @@ import org.apache.fop.area.Block; import org.apache.fop.area.BlockParent; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.Constants; import org.apache.fop.fo.properties.BreakPropertySet; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.SpaceProperty; +import org.apache.fop.fo.properties.KeepProperty; import org.apache.fop.layoutmgr.inline.InlineLayoutManager; import org.apache.fop.layoutmgr.inline.LineLayoutManager; import org.apache.fop.traits.MinOptMax; @@ -259,7 +261,7 @@ updateContentAreaIPDwithOverconstrainedAdjust(); - List returnedList = null; + List returnedList; List contentList = new LinkedList(); List returnList = new LinkedList(); @@ -274,7 +276,7 @@ if (!firstVisibleMarkServed) { addKnuthElementsForSpaceBefore(returnList, alignment); - context.updateKeepWithPreviousPending(getKeepWithPreviousStrength()); + context.updateKeepWithPreviousPending(getKeepWithPrevious()); } addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); @@ -316,7 +318,7 @@ } if (returnedList != null && returnedList.size() == 1 - && ((ListElement) returnedList.get(0)).isForcedBreak()) { + && ElementListUtils.startsWithForcedBreak(returnedList)) { if (curLM.isFinished() && !hasNextChildLM()) { // a descendant of this block has break-before @@ -342,7 +344,6 @@ // "wrap" the Position inside each element // moving the elements from contentList to returnList - returnedList = new LinkedList(); wrapPositionElements(contentList, returnList); return returnList; @@ -375,7 +376,6 @@ } /* end of extension */ - returnedList = new LinkedList(); wrapPositionElements(contentList, returnList); return returnList; @@ -394,7 +394,6 @@ } /* end of extension */ - returnedList = new LinkedList(); if (!contentList.isEmpty()) { wrapPositionElements(contentList, returnList); } else if (forcedBreakAfterLast == null) { @@ -417,7 +416,7 @@ returnList.add(forcedBreakAfterLast); } - context.updateKeepWithNextPending(getKeepWithNextStrength()); + context.updateKeepWithNextPending(getKeepWithNext()); setFinished(true); @@ -426,31 +425,31 @@ /** * Adds a break element to the content list between individual child elements. - * @param contentList the content list to populate - * @param context the current layout context + * @param contentList + * @param parentLC * @param childLC the currently active child layout context */ - protected void addInBetweenBreak(List contentList, LayoutContext context, - LayoutContext childLC) { + protected void addInBetweenBreak(List contentList, LayoutContext parentLC, + LayoutContext childLC) { + if (mustKeepTogether() - || context.isKeepWithNextPending() + || parentLC.isKeepWithNextPending() || childLC.isKeepWithPreviousPending()) { - int strength = getKeepTogetherStrength(); + Keep keep = getKeepTogether(); //Handle pending keep-with-next - strength = Math.max(strength, context.getKeepWithNextPending()); - context.clearKeepWithNextPending(); + keep = keep.compare(parentLC.getKeepWithNextPending()); + parentLC.clearKeepWithNextPending(); //Handle pending keep-with-previous from child LM - strength = Math.max(strength, childLC.getKeepWithPreviousPending()); + keep = keep.compare(childLC.getKeepWithPreviousPending()); childLC.clearKeepWithPreviousPending(); - int penalty = KeepUtil.getPenaltyForKeep(strength); - // add a penalty to forbid or discourage a break between blocks contentList.add(new BreakElement( - new Position(this), penalty, context)); + new Position(this), keep.getPenalty(), + keep.getContext(), parentLC)); return; } @@ -481,7 +480,7 @@ // add a null penalty to allow a break between blocks contentList.add(new BreakElement( - new Position(this), 0, context)); + new Position(this), 0, Constants.EN_AUTO, parentLC)); } } @@ -817,36 +816,80 @@ * Retrieves and returns the keep-together strength from the parent element. * @return the keep-together strength */ - protected int getParentKeepTogetherStrength() { - int strength = KEEP_AUTO; + protected Keep getParentKeepTogether() { + Keep keep = Keep.KEEP_AUTO; if (getParent() instanceof BlockLevelLayoutManager) { - strength = ((BlockLevelLayoutManager)getParent()).getKeepTogetherStrength(); + keep = ((BlockLevelLayoutManager)getParent()).getKeepTogether(); } else if (getParent() instanceof InlineLayoutManager) { if (((InlineLayoutManager) getParent()).mustKeepTogether()) { - strength = KEEP_ALWAYS; + keep = Keep.KEEP_ALWAYS; } //TODO Fix me //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength(); } - return strength; + return keep; } /** {@inheritDoc} */ public boolean mustKeepTogether() { - return getKeepTogetherStrength() > KEEP_AUTO; + return !getKeepTogether().isAuto(); } /** {@inheritDoc} */ public boolean mustKeepWithPrevious() { - return getKeepWithPreviousStrength() > KEEP_AUTO; + return !getKeepWithPrevious().isAuto(); } /** {@inheritDoc} */ public boolean mustKeepWithNext() { - return getKeepWithNextStrength() > KEEP_AUTO; + return !getKeepWithNext().isAuto(); } + /** {@inheritDoc} */ + public Keep getKeepTogether() { + Keep keep = Keep.getKeep(getKeepTogetherProperty()); + keep = keep.compare(getParentKeepTogether()); + return keep; + } + + /** {@inheritDoc} */ + public Keep getKeepWithPrevious() { + return Keep.getKeep(getKeepWithPreviousProperty()); + } + + /** {@inheritDoc} */ + public Keep getKeepWithNext() { + return Keep.getKeep(getKeepWithNextProperty()); + } + /** + * {@inheritDoc} + * Default implementation throws {@code IllegalStateException} + * Must be implemented by the subclass, if applicable. + */ + public KeepProperty getKeepTogetherProperty() { + throw new IllegalStateException(); + } + + /** + * {@inheritDoc} + * Default implementation throws {@code IllegalStateException} + * Must be implemented by the subclass, if applicable. + */ + public KeepProperty getKeepWithPreviousProperty() { + throw new IllegalStateException(); + } + + /** + * {@inheritDoc} + * Default implementation throws {@code IllegalStateException} + * Must be implemented by the subclass, if applicable. + */ + public KeepProperty getKeepWithNextProperty() { + throw new IllegalStateException(); + } + + /** * Adds the unresolved elements for border and padding to a layout context so break * possibilities can be properly constructed. * @param context the layout context Index: src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java =================================================================== --- src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java (revision 793568) +++ src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java (working copy) @@ -611,6 +611,14 @@ } /** + * Return the last node that yielded a too short line. + * @return the node corresponding to the last too short line + */ + protected final KnuthNode getLastTooShort() { + return this.lastTooShort; + } + + /** * Generic handler for a {@link KnuthElement} at the given {@code position}, * taking into account whether the preceding element was a box, and which * type(s) of breaks are allowed. @@ -647,7 +655,7 @@ /** * Handle a {@link KnuthBox}. - * Note: default implementation just adds the box's width + *
Note: default implementation just adds the box's width * to the total content width. Subclasses that do not keep track * of this themselves, but override this method, should remember * to call {@code super.handleBox(box)} to avoid unwanted side-effects. @@ -808,14 +816,21 @@ lastDeactivated = null; lastTooLong = null; for (int line = startLine; line < endLine; line++) { - if (!elementCanEndLine(element, line)) { - continue; - } for (KnuthNode node = getNode(line); node != null; node = node.next) { if (node.position == elementIdx) { continue; } int difference = computeDifference(node, element, elementIdx); + if (!elementCanEndLine(element, endLine)) { + if (difference >= 0) { + /* as long as the difference is positive, + * we don't really need a break anyway... + */ + log.trace("Skipping legal break"); + break; + } + } + double r = computeAdjustmentRatio(node, difference); int availableShrink = totalShrink - node.totalShrink; int availableStretch = totalStretch - node.totalStretch; Index: src/java/org/apache/fop/fo/flow/table/EffRow.java =================================================================== --- src/java/org/apache/fop/fo/flow/table/EffRow.java (revision 793568) +++ src/java/org/apache/fop/fo/flow/table/EffRow.java (working copy) @@ -23,8 +23,7 @@ import java.util.List; import org.apache.fop.fo.Constants; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; -import org.apache.fop.layoutmgr.KeepUtil; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.table.TableRowIterator; import org.apache.fop.traits.MinOptMax; import org.apache.fop.util.BreakUtil; @@ -170,20 +169,19 @@ * * @return the strength of the keep-with-previous constraint */ - public int getKeepWithPreviousStrength() { - int strength = BlockLevelLayoutManager.KEEP_AUTO; + public Keep getKeepWithPrevious() { + Keep keep = Keep.KEEP_AUTO; TableRow row = getTableRow(); if (row != null) { - strength = Math.max(strength, - KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithPrevious())); + keep = Keep.getKeep(row.getKeepWithPrevious()); } for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { GridUnit gu = (GridUnit) iter.next(); if (gu.isPrimary()) { - strength = Math.max(strength, gu.getPrimary().getKeepWithPreviousStrength()); + keep = keep.compare(gu.getPrimary().getKeepWithPrevious()); } } - return strength; + return keep; } /** @@ -192,20 +190,19 @@ * * @return the strength of the keep-with-next constraint */ - public int getKeepWithNextStrength() { - int strength = BlockLevelLayoutManager.KEEP_AUTO; + public Keep getKeepWithNext() { + Keep keep = Keep.KEEP_AUTO; TableRow row = getTableRow(); if (row != null) { - strength = Math.max(strength, - KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithNext())); + keep = Keep.getKeep(row.getKeepWithNext()); } for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { GridUnit gu = (GridUnit) iter.next(); if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) { - strength = Math.max(strength, gu.getPrimary().getKeepWithNextStrength()); + keep = keep.compare(gu.getPrimary().getKeepWithNext()); } } - return strength; + return keep; } /** @@ -213,16 +210,13 @@ * not take the parent table's keeps into account! * @return the keep-together strength */ - public int getKeepTogetherStrength() { + public Keep getKeepTogether() { TableRow row = getTableRow(); - int strength = BlockLevelLayoutManager.KEEP_AUTO; + Keep keep = Keep.KEEP_AUTO; if (row != null) { - strength = Math.max(strength, KeepUtil.getKeepStrength( - row.getKeepTogether().getWithinPage())); - strength = Math.max(strength, KeepUtil.getKeepStrength( - row.getKeepTogether().getWithinColumn())); + keep = Keep.getKeep(row.getKeepTogether()); } - return strength; + return keep; } /** Index: src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java =================================================================== --- src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java (revision 793568) +++ src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java (working copy) @@ -19,14 +19,13 @@ package org.apache.fop.fo.flow.table; -import java.util.LinkedList; import java.util.List; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; -import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.ElementListUtils; +import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.table.TableCellLayoutManager; /** @@ -54,8 +53,8 @@ private boolean isSeparateBorderModel; private int halfBorderSeparationBPD; - private int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO; - private int keepWithNext = BlockLevelLayoutManager.KEEP_AUTO; + private Keep keepWithPrevious = Keep.KEEP_AUTO; + private Keep keepWithNext = Keep.KEEP_AUTO; private int breakBefore = Constants.EN_AUTO; private int breakAfter = Constants.EN_AUTO; @@ -334,16 +333,16 @@ * * @return the keep-with-previous strength */ - public int getKeepWithPreviousStrength() { + public Keep getKeepWithPrevious() { return keepWithPrevious; } /** * Don't use, reserved for TableCellLM. TODO - * @param strength the keep strength + * @param keep the keep strength */ - public void setKeepWithPreviousStrength(int strength) { - this.keepWithPrevious = strength; + public void setKeepWithPrevious(Keep keep) { + this.keepWithPrevious = keep; } /** @@ -352,16 +351,16 @@ * * @return the keep-with-next strength */ - public int getKeepWithNextStrength() { + public Keep getKeepWithNext() { return keepWithNext; } /** * Don't use, reserved for TableCellLM. TODO - * @param strength the keep strength + * @param keep the keep strength */ - public void setKeepWithNextStrength(int strength) { - this.keepWithNext = strength; + public void setKeepWithNext(Keep keep) { + this.keepWithNext = keep; } /** Index: test/layoutengine/standard-testcases/inline_block_nested_6.xml =================================================================== --- test/layoutengine/standard-testcases/inline_block_nested_6.xml (revision 793568) +++ test/layoutengine/standard-testcases/inline_block_nested_6.xml (working copy) @@ -52,16 +52,15 @@ 5 - 6 + 5 - 6 + 3 - 5 - 3 + 14 Index: test/layoutengine/standard-testcases/keep_within-column_basic.xml =================================================================== --- test/layoutengine/standard-testcases/keep_within-column_basic.xml (revision 0) +++ test/layoutengine/standard-testcases/keep_within-column_basic.xml (revision 0) @@ -0,0 +1,141 @@ + + + + + +

+ This test checks whether keeps within-column are respected. +

+
+ + + + + + + + + + + + + [BOB-1] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-1] + + + [BOB-2] foo bar foo bar foo bar foo bar foo [EOB-2] + + + + + + [BOB-3] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + + [BOB-3a] foo bar foo bar foo bar foo bar foo [EOB-3a] + + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-3] + + + + + + [BOB-4] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + + [BOB-4a] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-4a] + + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-4] + + + + + + + [BOB-5a] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-5a] + + + [BOB-5b] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-5b] + + + [BOB-5c] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-5c] + + + + + + + + [BOB-6a] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-6a] + + + [BOB-6b] foo bar foo bar foo bar foo bar foo bar [EOB-6b] + + + [BOB-6c] foo bar foo bar foo bar foo bar foo bar + foo bar foo bar foo bar foo bar foo bar [EOB-6c] + + + + + + + + + + +
+ + Index: test/layoutengine/standard-testcases/table-row_keep-together.xml =================================================================== --- test/layoutengine/standard-testcases/table-row_keep-together.xml (revision 793568) +++ test/layoutengine/standard-testcases/table-row_keep-together.xml (working copy) @@ -64,10 +64,10 @@ - - - 3 + + + 5 Index: test/layoutengine/standard-testcases/table_keep-together.xml =================================================================== --- test/layoutengine/standard-testcases/table_keep-together.xml (revision 793568) +++ test/layoutengine/standard-testcases/table_keep-together.xml (working copy) @@ -101,9 +101,11 @@ - + + + 3