Browse Source

Bugzilla 46905: Added basic implementation for column-level keeps.

Also added one disabled-testcase for a remaining issue with page-level
keeps in multi-column layout.


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@807014 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Andreas L. Delmelle 14 years ago
parent
commit
a6b2b2e4b9
37 changed files with 1008 additions and 502 deletions
  1. 15
    21
      src/java/org/apache/fop/fo/flow/table/EffRow.java
  2. 11
    12
      src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
  3. 13
    18
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  4. 6
    9
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  5. 22
    8
      src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java
  6. 69
    23
      src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  7. 29
    20
      src/java/org/apache/fop/layoutmgr/BreakElement.java
  8. 16
    5
      src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
  9. 6
    6
      src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  10. 6
    6
      src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java
  11. 152
    0
      src/java/org/apache/fop/layoutmgr/Keep.java
  12. 0
    109
      src/java/org/apache/fop/layoutmgr/KeepUtil.java
  13. 42
    48
      src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
  14. 16
    17
      src/java/org/apache/fop/layoutmgr/LayoutContext.java
  15. 26
    21
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  16. 149
    0
      src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
  17. 44
    1
      src/java/org/apache/fop/layoutmgr/PageProvider.java
  18. 6
    6
      src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  19. 38
    21
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  20. 7
    10
      src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
  21. 8
    9
      src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
  22. 19
    23
      src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
  23. 11
    7
      src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
  24. 2
    2
      src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
  25. 6
    16
      src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java
  26. 5
    17
      src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java
  27. 22
    21
      src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
  28. 10
    11
      src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
  29. 9
    11
      src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
  30. 12
    16
      src/java/org/apache/fop/layoutmgr/table/TableStepper.java
  31. 3
    0
      status.xml
  32. 6
    0
      test/layoutengine/disabled-testcases.xml
  33. 3
    4
      test/layoutengine/standard-testcases/inline_block_nested_6.xml
  34. 155
    0
      test/layoutengine/standard-testcases/keep_within-column_basic.xml
  35. 58
    0
      test/layoutengine/standard-testcases/keep_within-page_multi-column_overflow.xml
  36. 3
    3
      test/layoutengine/standard-testcases/table-row_keep-together.xml
  37. 3
    1
      test/layoutengine/standard-testcases/table_keep-together.xml

+ 15
- 21
src/java/org/apache/fop/fo/flow/table/EffRow.java View File

@@ -23,8 +23,7 @@ import java.util.Iterator;
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 @@ public class EffRow {
*
* @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 @@ public class EffRow {
*
* @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 @@ public class EffRow {
* 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;
}

/**

+ 11
- 12
src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java View File

@@ -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 @@ public class PrimaryGridUnit extends GridUnit {
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 @@ public class PrimaryGridUnit extends GridUnit {
*
* @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 @@ public class PrimaryGridUnit extends GridUnit {
*
* @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;
}

/**

+ 13
- 18
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java View File

@@ -37,6 +37,7 @@ import org.apache.fop.datatypes.FODimension;
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 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(returnList, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
@@ -271,9 +272,9 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
//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 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
//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 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
context.clearPendingMarks();
addKnuthElementsForBreakAfter(returnList, context);

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);
return returnList;
@@ -1011,23 +1011,18 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
}

/** {@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();
}

/**

+ 6
- 9
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

@@ -207,21 +207,18 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
}

/** {@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} */

+ 22
- 8
src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java View File

@@ -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 @@ public interface BlockLevelLayoutManager extends LayoutManager {
/** 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 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* 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 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* 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,28 @@ public interface BlockLevelLayoutManager extends LayoutManager {
* 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.
* @return the keep-together property
*/
KeepProperty getKeepTogetherProperty();

/**
* Returns the keep-with-previous property specified on the FObj.
* @return the keep-together property
*/
KeepProperty getKeepWithPreviousProperty();

/**
* Returns the keep-with-next property specified on the FObj.
* @return the keep-together property
*/
KeepProperty getKeepWithNextProperty();
}

+ 69
- 23
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -31,9 +31,11 @@ import org.apache.fop.area.Area;
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;
@@ -258,7 +260,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

if (!firstVisibleMarkServed) {
addKnuthElementsForSpaceBefore(elements, alignment);
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}

addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
@@ -349,7 +351,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
elements.add(forcedBreakAfterLast);
}

context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);

@@ -375,31 +377,31 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

/**
* 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;
}

@@ -430,7 +432,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

// 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));
}
}

@@ -766,33 +768,77 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
* 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();
}

/**

+ 29
- 20
src/java/org/apache/fop/layoutmgr/BreakElement.java View File

@@ -41,7 +41,22 @@ public class BreakElement extends UnresolvedListElement {
* @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);
}

/**
@@ -65,6 +80,10 @@ public class BreakElement extends UnresolvedListElement {
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 @@ public class BreakElement extends UnresolvedListElement {

/** {@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);

+ 16
- 5
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java View File

@@ -610,6 +610,14 @@ public abstract class BreakingAlgorithm {
best.getNode(fitness));
}

/**
* 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
@@ -647,7 +655,7 @@ public abstract class BreakingAlgorithm {

/**
* Handle a {@link KnuthBox}.
* <em>Note: default implementation just adds the box's width
* <br/><em>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.</em>
@@ -808,14 +816,16 @@ public abstract class BreakingAlgorithm {
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, difference)) {
log.trace("Skipping legal break");
break;
}

double r = computeAdjustmentRatio(node, difference);
int availableShrink = totalShrink - node.totalShrink;
int availableStretch = totalStretch - node.totalStretch;
@@ -854,9 +864,10 @@ public abstract class BreakingAlgorithm {
* number.
* @param element the element
* @param line the line number
* @param difference
* @return {@code true} if the element can end the line
*/
protected boolean elementCanEndLine(KnuthElement element, int line) {
protected boolean elementCanEndLine(KnuthElement element, int line, int difference) {
return (!element.isPenalty()
|| element.getP() < KnuthElement.INFINITE);
}

+ 6
- 6
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java View File

@@ -181,18 +181,18 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
}

/** {@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} */

+ 6
- 6
src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java View File

@@ -92,18 +92,18 @@ public class FootnoteBodyLayoutManager extends BlockStackingLayoutManager {
}

/** {@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;
}

}

+ 152
- 0
src/java/org/apache/fop/layoutmgr/Keep.java View File

@@ -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 <a href="http://www.w3.org/TR/xsl/#d0e26492">keep properties</a>.
*/
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);
}
}

+ 0
- 109
src/java/org/apache/fop/layoutmgr/KeepUtil.java View File

@@ -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.
* <p>
* 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.
* <p>
* 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.
* <ul>
* <li>"auto": returns 0</li>
* <li>"always": returns KnuthElement.INFINITE</li>
* <li>otherwise: returns KnuthElement.INFINITE - 1</li>
* </ul>
* @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);
}
}

}

+ 42
- 48
src/java/org/apache/fop/layoutmgr/KnuthPenalty.java View File

@@ -45,7 +45,7 @@ public class KnuthPenalty extends KnuthElement {
public static final int FLAGGED_PENALTY = 50;

private int penalty;
private boolean bFlagged;
private boolean isFlagged;
private int breakClass = -1;

/**
@@ -55,12 +55,12 @@ public class KnuthPenalty extends KnuthElement {
* @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,18 +69,37 @@ public class KnuthPenalty extends KnuthElement {
* @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} */
@@ -105,7 +124,7 @@ public class KnuthPenalty extends KnuthElement {

/** @return true is this penalty is a flagged one. */
public boolean isFlagged() {
return bFlagged;
return isFlagged;
}

/** {@inheritDoc} */
@@ -121,14 +140,6 @@ public class KnuthPenalty extends KnuthElement {
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 @@ public class KnuthPenalty extends KnuthElement {
}
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();
}

}

+ 16
- 17
src/java/org/apache/fop/layoutmgr/LayoutContext.java View File

@@ -136,8 +136,8 @@ public class LayoutContext {
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;

@@ -227,7 +227,7 @@ public class LayoutContext {
* 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;
}

@@ -235,7 +235,7 @@ public class LayoutContext {
* 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;
}

@@ -243,14 +243,14 @@ public class LayoutContext {
* 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;
}

/**
@@ -263,18 +263,18 @@ public class LayoutContext {

/**
* 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);
}

/**
@@ -282,7 +282,7 @@ public class LayoutContext {
* @return true if a keep-with-next constraint is pending
*/
public boolean isKeepWithNextPending() {
return getKeepWithNextPending() != BlockLevelLayoutManager.KEEP_AUTO;
return !getKeepWithNextPending().isAuto();
}

/**
@@ -290,7 +290,7 @@ public class LayoutContext {
* @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) {
@@ -640,9 +640,8 @@ public class LayoutContext {
+ "\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" : "") + "]";
}

+ 26
- 21
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -451,9 +451,7 @@ public class PageBreaker extends AbstractBreaker {
pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished();
}

/**
* @return the current child flow layout manager
*/
/** @return the current child flow layout manager */
protected LayoutManager getCurrentChildLM() {
return childFLM;
}
@@ -472,44 +470,51 @@ public class PageBreaker extends AbstractBreaker {
*/
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;
}
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);
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);
}
}
}


+ 149
- 0
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java View File

@@ -96,6 +96,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
//Controls whether a single part should be forced if possible (ex. block-container)
private boolean favorSinglePart = false;

//Used to keep track of switches in keep-context
private int currentKeepContext = Constants.EN_AUTO;
private KnuthNode lastBeforeKeepContextSwitch;


public PageBreakingAlgorithm(LayoutManager topLevelLM,
PageProvider pageProvider,
PageBreakingLayoutListener layoutListener,
@@ -190,6 +195,72 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
footnoteElementIndex = -1;
}

/**
* {@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,
@@ -233,6 +304,28 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
}
}

/**
* {@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.
@@ -317,10 +410,66 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {

/** {@inheritDoc} */
protected void considerLegalBreak(KnuthElement element, int elementIdx) {
if (element.isPenalty()) {
int breakClass = ((KnuthPenalty) element).getBreakClass();
switch (breakClass) {
case Constants.EN_PAGE:
if (this.currentKeepContext != breakClass) {
this.lastBeforeKeepContextSwitch = getLastTooShort();
}
this.currentKeepContext = breakClass;
break;
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, int difference) {
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);
//|| (deferPart && difference < 0);
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;

+ 44
- 1
src/java/org/apache/fop/layoutmgr/PageProvider.java View File

@@ -146,6 +146,49 @@ public class PageProvider implements Constants {
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<x<partCount) which denotes the first part on the last page
* generated by the current element list.
@@ -272,4 +315,4 @@ public class PageProvider implements Constants {
return page;
}

}
}

+ 6
- 6
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java View File

@@ -314,18 +314,18 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
}

/** {@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;
}

}

+ 38
- 21
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -36,6 +36,7 @@ import org.apache.fop.datatypes.Numeric;
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;
@@ -46,7 +47,7 @@ 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.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
@@ -876,12 +877,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
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;
@@ -920,12 +921,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
&& 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();
@@ -1104,28 +1105,43 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}

/** {@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} */
@@ -1230,6 +1246,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
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

+ 7
- 10
src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java View File

@@ -29,10 +29,10 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListBlock;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
@@ -279,21 +279,18 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KeepUtil.getCombinedBlockLevelKeepStrength(
getListBlockFO().getKeepTogether());
strength = Math.max(strength, getParentKeepTogetherStrength());
return strength;
public KeepProperty getKeepTogetherProperty() {
return getListBlockFO().getKeepTogether();
}

/** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getListBlockFO().getKeepWithPrevious();
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getListBlockFO().getKeepWithPrevious());
public KeepProperty getKeepWithNextProperty() {
return getListBlockFO().getKeepWithNext();
}

/** {@inheritDoc} */

+ 8
- 9
src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java View File

@@ -28,8 +28,9 @@ import org.apache.fop.area.Block;
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 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager {
}

/** {@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;
}

}

+ 19
- 23
src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java View File

@@ -32,13 +32,13 @@ import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
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;
@@ -83,8 +83,8 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
private MinOptMax effSpaceBefore;
private MinOptMax effSpaceAfter;

private int keepWithNextPendingOnLabel;
private int keepWithNextPendingOnBody;
private Keep keepWithNextPendingOnLabel;
private Keep keepWithNextPendingOnBody;

private int listItemHeight;

@@ -254,8 +254,8 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager

context.updateKeepWithNextPending(this.keepWithNextPendingOnLabel);
context.updateKeepWithNextPending(this.keepWithNextPendingOnBody);
context.updateKeepWithNextPending(getKeepWithNextStrength());
context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithNextPending(getKeepWithNext());
context.updateKeepWithPreviousPending(getKeepWithPrevious());

setFinished(true);
resetSpaces();
@@ -276,16 +276,16 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
int step;
int addedBoxHeight = 0;
int keepWithNextActive = BlockLevelLayoutManager.KEEP_AUTO;
Keep keepWithNextActive = Keep.KEEP_AUTO;

LinkedList returnList = new LinkedList();
while ((step = getNextStep(elementLists, start, end, partialHeights)) > 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 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}

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 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}

/** {@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} */

+ 11
- 7
src/java/org/apache/fop/layoutmgr/table/ActiveCell.java View File

@@ -32,8 +32,8 @@ import org.apache.fop.fo.flow.table.ConditionalBorder;
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 @@ class ActiveCell {
/** 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 @@ class ActiveCell {
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 @@ class ActiveCell {
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 @@ class ActiveCell {
*/
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 @@ class ActiveCell {
}
}

int getKeepWithNextStrength() {
return keepWithNextStrength;
Keep getKeepWithNext() {
return keepWithNext;
}

int getPenaltyValue() {

+ 2
- 2
src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java View File

@@ -60,8 +60,8 @@ class RowGroupLayoutManager {
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();

+ 6
- 16
src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java View File

@@ -23,6 +23,7 @@ import org.apache.fop.area.Area;
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,19 +202,8 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = 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;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepWithNext());
@@ -221,12 +211,12 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepWithPrevious());
*/
}

}
}

+ 5
- 17
src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java View File

@@ -23,6 +23,7 @@ import org.apache.fop.area.Area;
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,21 +198,8 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = 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;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableCaptionFO().getKeepWithNext());
@@ -219,8 +207,8 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
}

/** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
/* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableCaptionFO().getKeepWithPrevious());

+ 22
- 21
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java View File

@@ -24,6 +24,7 @@ import java.util.List;

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,21 +32,23 @@ import org.apache.fop.fo.flow.table.ConditionalBorder;
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.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
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.LayoutManager;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceResolver;
@@ -138,9 +141,9 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
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 +156,12 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
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 +178,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
prevLM = curLM;
}
primaryGridUnit.setKeepWithNextStrength(context.getKeepWithNextPending());
primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending());

returnedList = new LinkedList();
if (!contentList.isEmpty()) {
@@ -195,7 +199,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
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 +560,23 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}

/** {@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 --------- //

+ 10
- 11
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java View File

@@ -35,10 +35,9 @@ import org.apache.fop.fo.flow.table.EffRow;
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 @@ public class TableContentLayoutManager implements PercentBaseContext {
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 @@ public class TableContentLayoutManager implements PercentBaseContext {

//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 @@ public class TableContentLayoutManager implements PercentBaseContext {
*/

//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 @@ public class TableContentLayoutManager implements PercentBaseContext {
breakElement = (BreakElement) elem;
}
breakElement.setPenaltyValue(penaltyValue);
breakElement.setBreakClass(breakBetween);
breakElement.setBreakClass(breakClass);
returnList.addAll(nextRowGroupElems);
breakBetween = context.getBreakAfter();
}

+ 9
- 11
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java View File

@@ -35,11 +35,11 @@ import org.apache.fop.fo.FONode;
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 @@ public class TableLayoutManager extends BlockStackingLayoutManager
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 @@ public class TableLayoutManager extends BlockStackingLayoutManager
}

/** {@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 --------- //

+ 12
- 16
src/java/org/apache/fop/layoutmgr/table/TableStepper.java View File

@@ -30,12 +30,10 @@ import org.apache.fop.fo.Constants;
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 @@ public class TableStepper {
}
}

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));
}

+ 3
- 0
status.xml View File

@@ -58,6 +58,9 @@
documents. Example: the fix of marks layering will be such a case when it's done.
-->
<release version="FOP Trunk" date="TBD">
<action context="Renderers" dev="AD" type="add" fixes-bug="46905">
Added basic implementation for column-keeps.
</action>
<action context="Renderers" dev="AD" type="fix" fixes-bug="46883">
Hotspot in AbstractGraphicsDrawingOrderContainer. Reduced time spent in the method
by introducing a member variable to hold the data-length.

+ 6
- 0
test/layoutengine/disabled-testcases.xml View File

@@ -216,4 +216,10 @@
<description>A soft hyphen should be a preferred as break compared to a
normal hyphenation point but is not.</description>
</testcase>
<testcase>
<name>Page-keep not respected in multi-column layout</name>
<file>keep_within-page_multi-column_overflow.xml</file>
<description>The block should cause overflow in the
last column on the page, rather than be broken.</description>
</testcase>
</disabled-testcases>

+ 3
- 4
test/layoutengine/standard-testcases/inline_block_nested_6.xml View File

@@ -52,16 +52,15 @@
<skip>5</skip>
<!-- penalty between blocks b11 and b12, set by InlineLM in b1 -->
<penalty w="0" p="0"/>
<skip>6</skip>
<skip>5</skip>
<!-- penalty between blocks b21 and b22, set by InlineLM in b2 -->
<!-- keep-together.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>6</skip>
<skip>3</skip>
<!-- penalty between blocks b31 and b32, set by InlineLM in b3 -->
<!-- keep-with-next.within-page="always" -->
<penalty w="0" p="1000"/>
<skip>5</skip>
<skip>3</skip>
<skip>14</skip>
</element-list>
</checks>
</testcase>

+ 155
- 0
test/layoutengine/standard-testcases/keep_within-column_basic.xml View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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$ -->
<testcase>
<info>
<p>
This test checks whether keeps within-column are respected.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-width="400pt" page-height="70pt">
<fo:region-body column-count="5" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" font-size="10pt">
<fo:flow flow-name="xsl-region-body">
<fo:block break-before="page">
<!-- simple test: keep the second block together within
one column, breaking the preceding block early
if necessary -->
<fo:block id="block-1">
[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]
</fo:block>
<fo:block id="block-2" keep-together.within-column="always">
[BOB-2] foo bar foo bar foo bar foo bar foo [EOB-2]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- same as the first, but now a nested block
with a higher integer value, and some content
following -->
<fo:block id="block-3" keep-together.within-column="5">
[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
<fo:block font-weight="bold" id="block-3a" keep-together.within-column="always">
[BOB-3a] foo bar foo bar foo bar foo bar foo [EOB-3a]
</fo:block>
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]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- nested block must be kept together within the same
page, while the outer block may be broken, if necessary -->
<fo:block font-style="italic" id="block-4" keep-together.within-column="5">
[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
<fo:block id="block-4a" keep-together.within-page="always">
[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]
</fo:block>
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]
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- test keep-with-next in conjunction with keep-together
respecting the default value for widows/orphans -->
<fo:block id="block-5">
<fo:block id="block-5a">
[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]
</fo:block>
<fo:block id="block-5b" keep-with-next.within-column="always">
[BOB-5b] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-5b]
</fo:block>
<fo:block id="block-5c" keep-together.within-column="always">
[BOB-5c] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-5c]
</fo:block>
</fo:block>
</fo:block>
<fo:block break-before="page">
<!-- test keep-together in conjunction with keep-with-previous -->
<fo:block id="block-6">
<fo:block id="block-6a">
[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]
</fo:block>
<fo:block id="block-6b" keep-together.within-column="always">
[BOB-6b] foo bar foo bar foo bar foo bar foo bar [EOB-6b]
</fo:block>
<fo:block id="block-6c" keep-with-previous.within-column="always">
[BOB-6c] foo bar foo bar foo bar foo bar foo bar
foo bar foo bar foo bar foo bar foo bar [EOB-6c]
</fo:block>
</fo:block>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<!-- check total page-count -->
<eval expected="10" xpath="count(//page)" />
<!-- block-2 should end up in its own column, column 4 -->
<eval expected="1" xpath="count(//block[@prod-id='block-2']/ancestor::flow)" />
<eval expected="3" xpath="count(//block[@prod-id='block-2']/ancestor::flow/preceding-sibling::flow)" />
<!-- block-3a should end up in its own column, column 5 -->
<eval expected="1" xpath="count(//block[@prod-id='block-3a']/ancestor::flow)" />
<eval expected="4" xpath="count(//block[@prod-id='block-3a']/ancestor::flow/preceding-sibling::flow)" />
<!-- block-4a should end up in its own page -->
<eval expected="1" xpath="count(//block[@prod-id='block-4a']/ancestor::page)" />
<!-- block 5c should end up in its own column, with two preceding lines from block 5b -->
<eval expected="1" xpath="count(//block[@prod-id='block-5c']/ancestor::flow)" />
<eval expected="2" xpath="count(//block[@prod-id='block-5c']/preceding-sibling::block/lineArea)" />
<!-- block 6b should end up in its own column, with two following lines from block 6c -->
<eval expected="1" xpath="count(//block[@prod-id='block-6b']/ancestor::flow)" />
<eval expected="2" xpath="count(//block[@prod-id='block-6b']/following-sibling::block/lineArea)" />
</checks>
</testcase>


+ 58
- 0
test/layoutengine/standard-testcases/keep_within-page_multi-column_overflow.xml View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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$ -->
<testcase>
<info>
<p>This test checks for a remaining issue after adding support
for keep-*.within column (see Bugzilla 46905).
keep-together.within-page does not work as expected in multi-column
layout. If the part does not fit into one page, it will ultimately
still be broken.
</p>
</info>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="page" page-width="400pt" page-height="70pt">
<fo:region-body column-count="5" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="page" font-size="10pt">
<fo:flow flow-name="xsl-region-body">
<!-- block must be kept together within the same page -->
<fo:block id="block-4a" keep-together.within-page="always">
[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 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]
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</fo>
<checks>
<eval expected="1" xpath="count(//pageViewport)" />
</checks>
</testcase>

+ 3
- 3
test/layoutengine/standard-testcases/table-row_keep-together.xml View File

@@ -64,10 +64,10 @@
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="28800"/>
<penalty w="0" p="0"/>
<box w="14400"/>
<skip>3</skip>
<penalty w="0" p="INF"/>
<box w="14400"/>
<skip>5</skip>
</element-list>
</checks>
</testcase>

+ 3
- 1
test/layoutengine/standard-testcases/table_keep-together.xml View File

@@ -101,7 +101,9 @@
<element-list category="breaker" index="0">
<box w="14400"/>
<penalty w="0" p="0"/>
<box w="28800"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="0"/>

Loading…
Cancel
Save