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

import java.util.List; import java.util.List;


import org.apache.fop.fo.Constants; 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.layoutmgr.table.TableRowIterator;
import org.apache.fop.traits.MinOptMax; import org.apache.fop.traits.MinOptMax;
import org.apache.fop.util.BreakUtil; import org.apache.fop.util.BreakUtil;
* *
* @return the strength of the keep-with-previous constraint * @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(); TableRow row = getTableRow();
if (row != null) { if (row != null) {
strength = Math.max(strength,
KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithPrevious()));
keep = Keep.getKeep(row.getKeepWithPrevious());
} }
for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next(); GridUnit gu = (GridUnit) iter.next();
if (gu.isPrimary()) { if (gu.isPrimary()) {
strength = Math.max(strength, gu.getPrimary().getKeepWithPreviousStrength());
keep = keep.compare(gu.getPrimary().getKeepWithPrevious());
} }
} }
return strength;
return keep;
} }


/** /**
* *
* @return the strength of the keep-with-next constraint * @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(); TableRow row = getTableRow();
if (row != null) { if (row != null) {
strength = Math.max(strength,
KeepUtil.getCombinedBlockLevelKeepStrength(row.getKeepWithNext()));
keep = Keep.getKeep(row.getKeepWithNext());
} }
for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { for (Iterator iter = gridUnits.iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next(); GridUnit gu = (GridUnit) iter.next();
if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) { 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;
} }


/** /**
* not take the parent table's keeps into account! * not take the parent table's keeps into account!
* @return the keep-together strength * @return the keep-together strength
*/ */
public int getKeepTogetherStrength() {
public Keep getKeepTogether() {
TableRow row = getTableRow(); TableRow row = getTableRow();
int strength = BlockLevelLayoutManager.KEEP_AUTO;
Keep keep = Keep.KEEP_AUTO;
if (row != null) { 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



package org.apache.fop.fo.flow.table; package org.apache.fop.fo.flow.table;


import java.util.LinkedList;
import java.util.List; import java.util.List;


import org.apache.fop.fo.Constants; import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FONode; import org.apache.fop.fo.FONode;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.table.TableCellLayoutManager; import org.apache.fop.layoutmgr.table.TableCellLayoutManager;


/** /**
private boolean isSeparateBorderModel; private boolean isSeparateBorderModel;
private int halfBorderSeparationBPD; 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 breakBefore = Constants.EN_AUTO;
private int breakAfter = Constants.EN_AUTO; private int breakAfter = Constants.EN_AUTO;


* *
* @return the keep-with-previous strength * @return the keep-with-previous strength
*/ */
public int getKeepWithPreviousStrength() {
public Keep getKeepWithPrevious() {
return keepWithPrevious; return keepWithPrevious;
} }


/** /**
* Don't use, reserved for TableCellLM. TODO * 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;
} }


/** /**
* *
* @return the keep-with-next strength * @return the keep-with-next strength
*/ */
public int getKeepWithNextStrength() {
public Keep getKeepWithNext() {
return keepWithNext; return keepWithNext;
} }


/** /**
* Don't use, reserved for TableCellLM. TODO * 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

import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.BlockContainer; import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.properties.CommonAbsolutePosition; 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.MinOptMax;
import org.apache.fop.traits.SpaceVal; import org.apache.fop.traits.SpaceVal;
import org.apache.fop.util.ListUtil; import org.apache.fop.util.ListUtil;


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


addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
//Spaces, border and padding to be repeated at each break //Spaces, border and padding to be repeated at each break
addPendingMarks(context); 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); LayoutContext childLC = new LayoutContext(0);
childLC.copyPendingMarksFrom(context); childLC.copyPendingMarksFrom(context);
// curLM is a ? // curLM is a ?
//Avoid NoSuchElementException below (happens with empty blocks) //Avoid NoSuchElementException below (happens with empty blocks)
continue; continue;
} }
if (((ListElement) ListUtil.getLast(returnedList))
.isForcedBreak()) {
if (ElementListUtils.endsWithForcedBreak(returnedList)) {
// a descendant of this block has break-after // a descendant of this block has break-after
if (curLM.isFinished()) { if (curLM.isFinished()) {
// there is no other content in this block; // there is no other content in this block;
context.clearPendingMarks(); context.clearPendingMarks();
addKnuthElementsForBreakAfter(returnList, context); addKnuthElementsForBreakAfter(returnList, context);


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


setFinished(true); setFinished(true);
return returnList; return returnList;
} }


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


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


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

} }


/** {@inheritDoc} */ /** {@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} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KeepUtil.getCombinedBlockLevelKeepStrength(getBlockFO().getKeepWithNext());
public KeepProperty getKeepWithPreviousProperty() {
return getBlockFO().getKeepWithPrevious();
} }


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


/** {@inheritDoc} */ /** {@inheritDoc} */

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



package org.apache.fop.layoutmgr; package org.apache.fop.layoutmgr;


import org.apache.fop.fo.properties.KeepProperty;

/** /**
* The interface for LayoutManagers which generate block areas * The interface for LayoutManagers which generate block areas
*/ */
/** Adjustment class: adjustment for line height */ /** Adjustment class: adjustment for line height */
int LINE_HEIGHT_ADJUSTMENT = 3; 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); int negotiateBPDAdjustment(int adj, KnuthElement lastElement);


void discardSpace(KnuthGlue spaceGlue); void discardSpace(KnuthGlue spaceGlue);
* Returns the keep-together strength for this element. * Returns the keep-together strength for this element.
* @return the keep-together strength * @return the keep-together strength
*/ */
int getKeepTogetherStrength();
Keep getKeepTogether();


/** /**
* @return true if this element must be kept together * @return true if this element must be kept together
* Returns the keep-with-previous strength for this element. * Returns the keep-with-previous strength for this element.
* @return the keep-with-previous strength * @return the keep-with-previous strength
*/ */
int getKeepWithPreviousStrength();
Keep getKeepWithPrevious();


/** /**
* @return true if this element must be kept with the previous element. * @return true if this element must be kept with the previous element.
* Returns the keep-with-next strength for this element. * Returns the keep-with-next strength for this element.
* @return the keep-with-next strength * @return the keep-with-next strength
*/ */
int getKeepWithNextStrength();
Keep getKeepWithNext();


/** /**
* @return true if this element must be kept with the next element. * @return true if this element must be kept with the next element.
*/ */
boolean mustKeepWithNext(); 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

import org.apache.fop.area.Block; import org.apache.fop.area.Block;
import org.apache.fop.area.BlockParent; import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.FObj; 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.BreakPropertySet;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.SpaceProperty; 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.InlineLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager; import org.apache.fop.layoutmgr.inline.LineLayoutManager;
import org.apache.fop.traits.MinOptMax; import org.apache.fop.traits.MinOptMax;


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


addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed); addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
elements.add(forcedBreakAfterLast); elements.add(forcedBreakAfterLast);
} }


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


setFinished(true); setFinished(true);




/** /**
* Adds a break element to the content list between individual child elements. * 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 * @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() if (mustKeepTogether()
|| context.isKeepWithNextPending()
|| parentLC.isKeepWithNextPending()
|| childLC.isKeepWithPreviousPending()) { || childLC.isKeepWithPreviousPending()) {


int strength = getKeepTogetherStrength();
Keep keep = getKeepTogether();


//Handle pending keep-with-next //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 //Handle pending keep-with-previous from child LM
strength = Math.max(strength, childLC.getKeepWithPreviousPending());
keep = keep.compare(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending(); childLC.clearKeepWithPreviousPending();


int penalty = KeepUtil.getPenaltyForKeep(strength);

// add a penalty to forbid or discourage a break between blocks // add a penalty to forbid or discourage a break between blocks
contentList.add(new BreakElement( contentList.add(new BreakElement(
new Position(this), penalty, context));
new Position(this), keep.getPenalty(),
keep.getContext(), parentLC));
return; return;
} }




// add a null penalty to allow a break between blocks // add a null penalty to allow a break between blocks
contentList.add(new BreakElement( contentList.add(new BreakElement(
new Position(this), 0, context));
new Position(this), 0, Constants.EN_AUTO, parentLC));
} }
} }


* Retrieves and returns the keep-together strength from the parent element. * Retrieves and returns the keep-together strength from the parent element.
* @return the keep-together strength * @return the keep-together strength
*/ */
protected int getParentKeepTogetherStrength() {
int strength = KEEP_AUTO;
protected Keep getParentKeepTogether() {
Keep keep = Keep.KEEP_AUTO;
if (getParent() instanceof BlockLevelLayoutManager) { if (getParent() instanceof BlockLevelLayoutManager) {
strength = ((BlockLevelLayoutManager)getParent()).getKeepTogetherStrength();
keep = ((BlockLevelLayoutManager)getParent()).getKeepTogether();
} else if (getParent() instanceof InlineLayoutManager) { } else if (getParent() instanceof InlineLayoutManager) {
if (((InlineLayoutManager) getParent()).mustKeepTogether()) { if (((InlineLayoutManager) getParent()).mustKeepTogether()) {
strength = KEEP_ALWAYS;
keep = Keep.KEEP_ALWAYS;
} }
//TODO Fix me //TODO Fix me
//strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength(); //strength = ((InlineLayoutManager) getParent()).getKeepTogetherStrength();
} }
return strength;
return keep;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean mustKeepTogether() { public boolean mustKeepTogether() {
return getKeepTogetherStrength() > KEEP_AUTO;
return !getKeepTogether().isAuto();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean mustKeepWithPrevious() { public boolean mustKeepWithPrevious() {
return getKeepWithPreviousStrength() > KEEP_AUTO;
return !getKeepWithPrevious().isAuto();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean mustKeepWithNext() { 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

* @param context the layout context which contains the pending conditional elements * @param context the layout context which contains the pending conditional elements
*/ */
public BreakElement(Position position, int penaltyValue, LayoutContext context) { 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);
} }


/** /**
this.pendingAfterMarks = context.getPendingAfterMarks(); this.pendingAfterMarks = context.getPendingAfterMarks();
} }


private static String getBreakClassName(int breakClass) {
return AbstractBreaker.getBreakClassName(breakClass);
}

/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean isConditional() { public boolean isConditional() {
return false; //Does not really apply here return false; //Does not really apply here


/** {@inheritDoc} */ /** {@inheritDoc} */
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer();
StringBuffer sb = new StringBuffer(64);
sb.append("BreakPossibility[p:"); sb.append("BreakPossibility[p:");
sb.append(this.penaltyValue);
sb.append(KnuthPenalty.valueOf(this.penaltyValue));
if (isForcedBreak()) { 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("; w:");
sb.append(penaltyWidth); sb.append(penaltyWidth);

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

best.getNode(fitness)); 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}, * Generic handler for a {@link KnuthElement} at the given {@code position},
* taking into account whether the preceding element was a box, and which * taking into account whether the preceding element was a box, and which


/** /**
* Handle a {@link KnuthBox}. * 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 * to the total content width. Subclasses that do not keep track
* of this themselves, but override this method, should remember * of this themselves, but override this method, should remember
* to call {@code super.handleBox(box)} to avoid unwanted side-effects.</em> * to call {@code super.handleBox(box)} to avoid unwanted side-effects.</em>
lastDeactivated = null; lastDeactivated = null;
lastTooLong = null; lastTooLong = null;
for (int line = startLine; line < endLine; line++) { for (int line = startLine; line < endLine; line++) {
if (!elementCanEndLine(element, line)) {
continue;
}
for (KnuthNode node = getNode(line); node != null; node = node.next) { for (KnuthNode node = getNode(line); node != null; node = node.next) {
if (node.position == elementIdx) { if (node.position == elementIdx) {
continue; continue;
} }
int difference = computeDifference(node, element, elementIdx); int difference = computeDifference(node, element, elementIdx);
if (!elementCanEndLine(element, endLine, difference)) {
log.trace("Skipping legal break");
break;
}

double r = computeAdjustmentRatio(node, difference); double r = computeAdjustmentRatio(node, difference);
int availableShrink = totalShrink - node.totalShrink; int availableShrink = totalShrink - node.totalShrink;
int availableStretch = totalStretch - node.totalStretch; int availableStretch = totalStretch - node.totalStretch;
* number. * number.
* @param element the element * @param element the element
* @param line the line number * @param line the line number
* @param difference
* @return {@code true} if the element can end the line * @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() return (!element.isPenalty()
|| element.getP() < KnuthElement.INFINITE); || element.getP() < KnuthElement.INFINITE);
} }

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

} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepTogetherStrength() {
return KEEP_AUTO;
public Keep getKeepTogether() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */

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

} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepTogetherStrength() {
return getParentKeepTogetherStrength();
public Keep getKeepTogether() {
return getParentKeepTogether();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
} }


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

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

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

public static final int FLAGGED_PENALTY = 50; public static final int FLAGGED_PENALTY = 50;


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


/** /**
* @param p the penalty value of this penalty * @param p the penalty value of this penalty
* @param f is this penalty flagged? * @param f is this penalty flagged?
* @param pos the Position stored in this penalty * @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; penalty = p;
bFlagged = f;
isFlagged = f;
} }


/** /**
* @param w the width of this penalty * @param w the width of this penalty
* @param p the penalty value of this penalty * @param p the penalty value of this penalty
* @param f is this penalty flagged? * @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_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
* {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}) * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
* @param pos the Position stored in this penalty * @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, 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} */ /** {@inheritDoc} */


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


/** {@inheritDoc} */ /** {@inheritDoc} */
return breakClass; 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} */ /** {@inheritDoc} */
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(64); StringBuffer sb = new StringBuffer(64);
} }
sb.append("penalty"); sb.append("penalty");
sb.append(" p="); 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(" [flagged]");
} }
sb.append(" w="); sb.append(" w=");
sb.append(getW()); sb.append(getW());
if (isForcedBreak()) { 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(); return sb.toString();
} }

} }

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

private int breakBefore; private int breakBefore;
private int breakAfter; 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; private int disableColumnBalancing;


* Returns the strength of a keep-with-next currently pending. * Returns the strength of a keep-with-next currently pending.
* @return the keep-with-next strength * @return the keep-with-next strength
*/ */
public int getKeepWithNextPending() {
public Keep getKeepWithNextPending() {
return this.pendingKeepWithNext; return this.pendingKeepWithNext;
} }


* Returns the strength of a keep-with-previous currently pending. * Returns the strength of a keep-with-previous currently pending.
* @return the keep-with-previous strength * @return the keep-with-previous strength
*/ */
public int getKeepWithPreviousPending() {
public Keep getKeepWithPreviousPending() {
return this.pendingKeepWithPrevious; return this.pendingKeepWithPrevious;
} }


* Clears any pending keep-with-next strength. * Clears any pending keep-with-next strength.
*/ */
public void clearKeepWithNextPending() { public void clearKeepWithNextPending() {
this.pendingKeepWithNext = BlockLevelLayoutManager.KEEP_AUTO;
this.pendingKeepWithNext = Keep.KEEP_AUTO;
} }


/** /**
* Clears any pending keep-with-previous strength. * Clears any pending keep-with-previous strength.
*/ */
public void clearKeepWithPreviousPending() { public void clearKeepWithPreviousPending() {
this.pendingKeepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
this.pendingKeepWithPrevious = Keep.KEEP_AUTO;
} }


/** /**


/** /**
* Updates the currently pending keep-with-next strength. * 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. * 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);
} }


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


/** /**
* @return true if a keep-with-previous constraint is pending * @return true if a keep-with-previous constraint is pending
*/ */
public boolean isKeepWithPreviousPending() { public boolean isKeepWithPreviousPending() {
return getKeepWithPreviousPending() != BlockLevelLayoutManager.KEEP_AUTO;
return !getKeepWithPreviousPending().isAuto();
} }


public void setLeadingSpace(SpaceSpecifier space) { public void setLeadingSpace(SpaceSpecifier space) {
+ "\nStarts New Area: \t" + startsNewArea() + "\nStarts New Area: \t" + startsNewArea()
+ "\nIs Last Area: \t" + isLastArea() + "\nIs Last Area: \t" + isLastArea()
+ "\nTry Hyphenate: \t" + tryHyphenate() + "\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" : "") + "][" + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "]["
+ (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]"; + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]";
} }

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

pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished(); pslm.getCurrentPV().getCurrentSpan().notifyFlowsFinished();
} }


/**
* @return the current child flow layout manager
*/
/** @return the current child flow layout manager */
protected LayoutManager getCurrentChildLM() { protected LayoutManager getCurrentChildLM() {
return childFLM; return childFLM;
} }
*/ */
private void handleBreakTrait(int breakVal) { private void handleBreakTrait(int breakVal) {
Page curPage = pslm.getCurrentPage(); Page curPage = pslm.getCurrentPage();
if (breakVal == Constants.EN_ALL) {
switch (breakVal) {
case Constants.EN_ALL:
//break due to span change in multi-column layout //break due to span change in multi-column layout
curPage.getPageViewport().createSpan(true); curPage.getPageViewport().createSpan(true);
return; return;
} else if (breakVal == Constants.EN_NONE) {
case Constants.EN_NONE:
curPage.getPageViewport().createSpan(false); curPage.getPageViewport().createSpan(false);
return; 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(); PageViewport pv = curPage.getPageViewport();


//Check if previous page was spanned //Check if previous page was spanned
boolean forceNewPageWithSpan = false; boolean forceNewPageWithSpan = false;
RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion( RegionBody rb = (RegionBody)curPage.getSimplePageMaster().getRegion(
Constants.FO_REGION_BODY); Constants.FO_REGION_BODY);
if (rb.getColumnCount() > 1
&& pv.getCurrentSpan().getColumnCount() == 1) {
forceNewPageWithSpan = true;
}
forceNewPageWithSpan
= (rb.getColumnCount() > 1
&& pv.getCurrentSpan().getColumnCount() == 1);


if (forceNewPageWithSpan) { if (forceNewPageWithSpan) {
log.trace("Forcing new page with span");
curPage = pslm.makeNewPage(false, false); curPage = pslm.makeNewPage(false, false);
curPage.getPageViewport().createSpan(true); curPage.getPageViewport().createSpan(true);
} else if (pv.getCurrentSpan().hasMoreFlows()) { } else if (pv.getCurrentSpan().hasMoreFlows()) {
log.trace("Moving to next flow");
pv.getCurrentSpan().moveToNextFlow(); pv.getCurrentSpan().moveToNextFlow();
} else { } else {
curPage = pslm.makeNewPage(false, false);
log.trace("Making new page");
/*curPage = */pslm.makeNewPage(false, false);
} }
return; 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

//Controls whether a single part should be forced if possible (ex. block-container) //Controls whether a single part should be forced if possible (ex. block-container)
private boolean favorSinglePart = false; 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, public PageBreakingAlgorithm(LayoutManager topLevelLM,
PageProvider pageProvider, PageProvider pageProvider,
PageBreakingLayoutListener layoutListener, PageBreakingLayoutListener layoutListener,
footnoteElementIndex = -1; 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} */ /** {@inheritDoc} */
protected KnuthNode createNode(int position, int line, int fitness, protected KnuthNode createNode(int position, int line, int fitness,
int totalWidth, int totalStretch, int totalShrink, int totalWidth, int totalStretch, int totalShrink,
} }
} }


/**
* {@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 * Handles the footnotes cited inside a block-level box. Updates footnotesList and the
* value of totalFootnotesLength with the lengths of the given footnotes. * value of totalFootnotesLength with the lengths of the given footnotes.


/** {@inheritDoc} */ /** {@inheritDoc} */
protected void considerLegalBreak(KnuthElement element, int elementIdx) { 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); super.considerLegalBreak(element, elementIdx);
newFootnotes = false; 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, protected int computeDifference(KnuthNode activeNode, KnuthElement element,
int elementIndex) { int elementIndex) {
KnuthPageNode pageNode = (KnuthPageNode) activeNode; KnuthPageNode pageNode = (KnuthPageNode) activeNode;

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

return this.lastReportedBPD; 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 * Returns the part index (0<x<partCount) which denotes the first part on the last page
* generated by the current element list. * generated by the current element list.
return page; return page;
} }


}
}

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

} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepTogetherStrength() {
return KEEP_AUTO;
public Keep getKeepTogether() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
} }


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

import org.apache.fop.fo.Constants; import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Block; import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.properties.CommonHyphenation; 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.Font;
import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontInfo;
import org.apache.fop.fonts.FontTriplet; import org.apache.fop.fonts.FontTriplet;
import org.apache.fop.layoutmgr.BreakingAlgorithm; import org.apache.fop.layoutmgr.BreakingAlgorithm;
import org.apache.fop.layoutmgr.ElementListObserver; import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.InlineKnuthSequence; 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.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
for (int p = 0; p < knuthParagraphs.size(); p++) { for (int p = 0; p < knuthParagraphs.size(); p++) {
// penalty between paragraphs // penalty between paragraphs
if (p > 0) { 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; LineLayoutPossibilities llPoss;
&& i >= fobj.getOrphans() && i >= fobj.getOrphans()
&& i <= llPoss.getChosenLineCount() - fobj.getWidows()) { && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
// penalty allowing a page break between lines // 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 int endIndex
= ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
} }


/** {@inheritDoc} */ /** {@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} */ /** {@inheritDoc} */
public boolean mustKeepWithPrevious() { public boolean mustKeepWithPrevious() {
return getKeepWithPreviousStrength() > KEEP_AUTO;
return !getKeepWithPrevious().isAuto();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public boolean mustKeepWithNext() { public boolean mustKeepWithNext() {
return getKeepWithNextStrength() > KEEP_AUTO;
return !getKeepWithNext().isAuto();
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithPreviousStrength() {
return KEEP_AUTO;
public Keep getKeepWithPrevious() {
return Keep.KEEP_AUTO;
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
break; break;
} }
//TODO Something's not right here. See block_hyphenation_linefeed_preserve.xml //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; // collect word fragments, ignoring auxiliary elements;
// each word fragment was created by a different TextLM // each word fragment was created by a different TextLM

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

import org.apache.fop.area.Area; import org.apache.fop.area.Area;
import org.apache.fop.area.Block; import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.ListBlock; 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.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.ConditionalElementListener; import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition; import org.apache.fop.layoutmgr.NonLeafPosition;
} }


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


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


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


/** {@inheritDoc} */ /** {@inheritDoc} */

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

import org.apache.fop.fo.flow.AbstractListItemPart; import org.apache.fop.fo.flow.AbstractListItemPart;
import org.apache.fop.fo.flow.ListItemBody; import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel; 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.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition; import org.apache.fop.layoutmgr.NonLeafPosition;
} }


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


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepWithNextStrength() {
return KEEP_AUTO;
public Keep getKeepWithNext() {
return Keep.KEEP_AUTO;
} }


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

import org.apache.fop.fo.flow.ListItem; import org.apache.fop.fo.flow.ListItem;
import org.apache.fop.fo.flow.ListItemBody; import org.apache.fop.fo.flow.ListItemBody;
import org.apache.fop.fo.flow.ListItemLabel; 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.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener; import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.ElementListObserver; import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils; 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.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
private MinOptMax effSpaceBefore; private MinOptMax effSpaceBefore;
private MinOptMax effSpaceAfter; private MinOptMax effSpaceAfter;


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


private int listItemHeight; private int listItemHeight;




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


setFinished(true); setFinished(true);
resetSpaces(); resetSpaces();
int totalHeight = Math.max(fullHeights[0], fullHeights[1]); int totalHeight = Math.max(fullHeights[0], fullHeights[1]);
int step; int step;
int addedBoxHeight = 0; int addedBoxHeight = 0;
int keepWithNextActive = BlockLevelLayoutManager.KEEP_AUTO;
Keep keepWithNextActive = Keep.KEEP_AUTO;


LinkedList returnList = new LinkedList(); LinkedList returnList = new LinkedList();
while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) { while ((step = getNextStep(elementLists, start, end, partialHeights)) > 0) {


if (end[0] + 1 == elementLists[0].size()) { if (end[0] + 1 == elementLists[0].size()) {
keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnLabel);
keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnLabel);
} }
if (end[1] + 1 == elementLists[1].size()) { if (end[1] + 1 == elementLists[1].size()) {
keepWithNextActive = Math.max(keepWithNextActive, keepWithNextPendingOnBody);
keepWithNextActive = keepWithNextActive.compare(keepWithNextPendingOnBody);
} }


// compute penalty height and box height // compute penalty height and box height
} }


if (addedBoxHeight < totalHeight) { 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; int p = stepPenalty;
if (p > -KnuthElement.INFINITE) { 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));
} }
} }


} }


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


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


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


/** {@inheritDoc} */ /** {@inheritDoc} */

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

import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
/** True if the next CellPart that will be created will be the last one for this cell. */ /** True if the next CellPart that will be created will be the last one for this cell. */
private boolean lastCellPart; private boolean lastCellPart;


private int keepWithNextStrength;
private Keep keepWithNext;


private int spanIndex = 0; private int spanIndex = 0;


includedLength = -1; // Avoid troubles with cells having content of zero length includedLength = -1; // Avoid troubles with cells having content of zero length
totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList); totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1; endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
keepWithNextStrength = BlockLevelLayoutManager.KEEP_AUTO;
keepWithNext = Keep.KEEP_AUTO;
remainingLength = totalLength - previousRowsLength; remainingLength = totalLength - previousRowsLength;


afterNextStep = new Step(previousRowsLength); afterNextStep = new Step(previousRowsLength);
KnuthElement el = (KnuthElement) knuthIter.next(); KnuthElement el = (KnuthElement) knuthIter.next();
if (el.isPenalty()) { if (el.isPenalty()) {
prevIsBox = false; 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 // First legal break point
breakFound = true; breakFound = true;
KnuthPenalty p = (KnuthPenalty) el; KnuthPenalty p = (KnuthPenalty) el;
*/ */
CellPart createCellPart() { CellPart createCellPart() {
if (nextStep.end + 1 == elementList.size()) { 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 // TODO if keep-with-next is set on the row, must every cell of the row
// contribute some content from children blocks? // contribute some content from children blocks?
// see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/ // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/
} }
} }


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


int getPenaltyValue() { int getPenaltyValue() {

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

LinkedList returnList = new LinkedList(); LinkedList returnList = new LinkedList();
createElementsForRowGroup(context, alignment, bodyType, returnList); 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; int breakBefore = Constants.EN_AUTO;
TableRow firstRow = rowGroup[0].getTableRow(); TableRow firstRow = rowGroup[0].getTableRow();

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

import org.apache.fop.area.Block; import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.table.TableAndCaption; import org.apache.fop.fo.flow.table.TableAndCaption;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.PositionIterator;


} }


/** {@inheritDoc} */ /** {@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! /* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength( return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableAndCaptionFO().getKeepWithNext()); getTableAndCaptionFO().getKeepWithNext());
} }


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


}
}

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

import org.apache.fop.area.Block; import org.apache.fop.area.Block;
import org.apache.fop.fo.flow.table.TableCaption; import org.apache.fop.fo.flow.table.TableCaption;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.PositionIterator;


} }


/** {@inheritDoc} */ /** {@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! /* TODO Complete me!
return KeepUtil.getCombinedBlockLevelKeepStrength( return KeepUtil.getCombinedBlockLevelKeepStrength(
getTableCaptionFO().getKeepWithNext()); getTableCaptionFO().getKeepWithNext());
} }


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

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



import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area; import org.apache.fop.area.Area;
import org.apache.fop.area.Block; import org.apache.fop.area.Block;
import org.apache.fop.area.Trait; import org.apache.fop.area.Trait;
import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table; 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.TableCell;
import org.apache.fop.fo.flow.table.TableColumn; 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.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.layoutmgr.AreaAdditionUtil; import org.apache.fop.layoutmgr.AreaAdditionUtil;
import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; 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.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceResolver; import org.apache.fop.layoutmgr.SpaceResolver;
List contentList = new LinkedList(); List contentList = new LinkedList();
List returnList = 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); LayoutContext childLC = new LayoutContext(0);
// curLM is a ? // curLM is a ?
childLC.setStackLimitBP(MinOptMax.subtract(context childLC.setStackLimitBP(MinOptMax.subtract(context
log.debug("child LM signals pending keep with next"); log.debug("child LM signals pending keep with next");
} }
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
primaryGridUnit.setKeepWithPreviousStrength(childLC.getKeepWithPreviousPending());
primaryGridUnit.setKeepWithPrevious(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending(); childLC.clearKeepWithPreviousPending();
} }


if (prevLM != null) {
if (prevLM != null
&& !ElementListUtils.endsWithForcedBreak(contentList)) {
// there is a block handled by prevLM // there is a block handled by prevLM
// before the one handled by curLM // before the one handled by curLM
addInBetweenBreak(contentList, context, childLC); addInBetweenBreak(contentList, context, childLC);
} }
prevLM = curLM; prevLM = curLM;
} }
primaryGridUnit.setKeepWithNextStrength(context.getKeepWithNextPending());
primaryGridUnit.setKeepWithNext(context.getKeepWithNextPending());


returnedList = new LinkedList(); returnedList = new LinkedList();
if (!contentList.isEmpty()) { if (!contentList.isEmpty()) {
} }
final KnuthElement lastItem = (KnuthElement) ListUtil final KnuthElement lastItem = (KnuthElement) ListUtil
.getLast(returnList); .getLast(returnList);
if (((KnuthElement) lastItem).isForcedBreak()) {
if (lastItem.isForcedBreak()) {
KnuthPenalty p = (KnuthPenalty) lastItem; KnuthPenalty p = (KnuthPenalty) lastItem;
primaryGridUnit.setBreakAfter(p.getBreakClass()); primaryGridUnit.setBreakAfter(p.getBreakClass());
p.setP(0); p.setP(0);
} }


/** {@inheritDoc} */ /** {@inheritDoc} */
public int getKeepTogetherStrength() {
int strength = KEEP_AUTO;
public Keep getKeepTogether() {
Keep keep = Keep.KEEP_AUTO;
if (primaryGridUnit.getRow() != null) { 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} */ /** {@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} */ /** {@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 --------- // // --------- Property Resolution related functions --------- //

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

import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit;
import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TablePart; 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.BreakElement;
import org.apache.fop.layoutmgr.ElementListUtils; 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.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthGlue;
context.clearKeepsPending(); context.clearKeepsPending();
context.setBreakBefore(Constants.EN_AUTO); context.setBreakBefore(Constants.EN_AUTO);
context.setBreakAfter(Constants.EN_AUTO); context.setBreakAfter(Constants.EN_AUTO);
int keepWithPrevious = BlockLevelLayoutManager.KEEP_AUTO;
Keep keepWithPrevious = Keep.KEEP_AUTO;
int breakBefore = Constants.EN_AUTO; int breakBefore = Constants.EN_AUTO;
if (rowGroup != null) { if (rowGroup != null) {
RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
stepper); stepper);
List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
keepWithPrevious = Math.max(keepWithPrevious, context.getKeepWithPreviousPending());
keepWithPrevious = keepWithPrevious.compare(context.getKeepWithPreviousPending());
breakBefore = context.getBreakBefore(); breakBefore = context.getBreakBefore();
int breakBetween = context.getBreakAfter(); int breakBetween = context.getBreakAfter();
returnList.addAll(nextRowGroupElems); returnList.addAll(nextRowGroupElems);


//Note previous pending keep-with-next and clear the strength //Note previous pending keep-with-next and clear the strength
//(as the layout context is reused) //(as the layout context is reused)
int keepWithNextPending = context.getKeepWithNextPending();
Keep keepWithNextPending = context.getKeepWithNextPending();
context.clearKeepWithNextPending(); context.clearKeepWithNextPending();


//Get elements for next row group //Get elements for next row group
*/ */


//Determine keep constraints //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(); 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, breakBetween = BreakUtil.compareBreakClasses(breakBetween,
context.getBreakBefore()); context.getBreakBefore());
if (breakBetween != Constants.EN_AUTO) { if (breakBetween != Constants.EN_AUTO) {
penaltyValue = -KnuthElement.INFINITE; penaltyValue = -KnuthElement.INFINITE;
breakClass = breakBetween;
} }
BreakElement breakElement; BreakElement breakElement;
ListIterator elemIter = returnList.listIterator(returnList.size()); ListIterator elemIter = returnList.listIterator(returnList.size());
breakElement = (BreakElement) elem; breakElement = (BreakElement) elem;
} }
breakElement.setPenaltyValue(penaltyValue); breakElement.setPenaltyValue(penaltyValue);
breakElement.setBreakClass(breakBetween);
breakElement.setBreakClass(breakClass);
returnList.addAll(nextRowGroupElems); returnList.addAll(nextRowGroupElems);
breakBetween = context.getBreakAfter(); breakBetween = context.getBreakAfter();
} }

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

import org.apache.fop.fo.FObj; import org.apache.fop.fo.FObj;
import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableColumn; 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.BlockLevelEventProducer;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ConditionalElementListener; import org.apache.fop.layoutmgr.ConditionalElementListener;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
log.debug(contentKnuthElements); log.debug(contentKnuthElements);
wrapPositionElements(contentKnuthElements, returnList); wrapPositionElements(contentKnuthElements, returnList);


context.updateKeepWithPreviousPending(getKeepWithPreviousStrength());
context.updateKeepWithPreviousPending(getKeepWithPrevious());
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());


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


if (getTable().isSeparateBorderModel()) { if (getTable().isSeparateBorderModel()) {
} }


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


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


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


// --------- Property Resolution related functions --------- // // --------- Property Resolution related functions --------- //

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

import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.EffRow;
import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.GridUnit;
import org.apache.fop.fo.flow.table.PrimaryGridUnit; 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.BreakElement;
import org.apache.fop.layoutmgr.KeepUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBlockBox;
import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthGlue;
import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutContext;
} }
} }


int strength = BlockLevelLayoutManager.KEEP_AUTO;
Keep keep = Keep.KEEP_AUTO;
int stepPenalty = 0; int stepPenalty = 0;
for (Iterator iter = activeCells.iterator(); iter.hasNext();) { for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
ActiveCell activeCell = (ActiveCell) iter.next(); ActiveCell activeCell = (ActiveCell) iter.next();
strength = Math.max(strength, activeCell.getKeepWithNextStrength());
keep = keep.compare(activeCell.getKeepWithNext());
stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue()); stepPenalty = Math.max(stepPenalty, activeCell.getPenaltyValue());
} }
if (!rowFinished) { 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... //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) { } 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, nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
rowGroup[activeRowIndex].getBreakAfter()); rowGroup[activeRowIndex].getBreakAfter());
nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
rowGroup[activeRowIndex + 1].getBreakBefore()); rowGroup[activeRowIndex + 1].getBreakBefore());
} }
int p = KeepUtil.getPenaltyForKeep(strength);
int p = keep.getPenalty();
if (rowHeightSmallerThanFirstStep) { if (rowHeightSmallerThanFirstStep) {
rowHeightSmallerThanFirstStep = false; rowHeightSmallerThanFirstStep = false;
p = KnuthPenalty.INFINITE; 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) { if (nextBreakClass != Constants.EN_AUTO) {
log.trace("Forced break encountered"); log.trace("Forced break encountered");
p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0) 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) { if (penaltyOrGlueLen < 0) {
returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true)); returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true));
} }

+ 3
- 0
status.xml View File

documents. Example: the fix of marks layering will be such a case when it's done. documents. Example: the fix of marks layering will be such a case when it's done.
--> -->
<release version="FOP Trunk" date="TBD"> <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"> <action context="Renderers" dev="AD" type="fix" fixes-bug="46883">
Hotspot in AbstractGraphicsDrawingOrderContainer. Reduced time spent in the method Hotspot in AbstractGraphicsDrawingOrderContainer. Reduced time spent in the method
by introducing a member variable to hold the data-length. by introducing a member variable to hold the data-length.

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

<description>A soft hyphen should be a preferred as break compared to a <description>A soft hyphen should be a preferred as break compared to a
normal hyphenation point but is not.</description> normal hyphenation point but is not.</description>
</testcase> </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> </disabled-testcases>

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

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

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

<?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

<?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

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

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

<element-list category="breaker" index="0"> <element-list category="breaker" index="0">
<box w="14400"/> <box w="14400"/>
<penalty w="0" p="0"/> <penalty w="0" p="0"/>
<box w="28800"/>
<box w="14400"/>
<penalty w="0" p="INF"/>
<box w="14400"/>
<penalty w="0" p="INF"/> <penalty w="0" p="INF"/>
<box w="14400"/> <box w="14400"/>
<penalty w="0" p="0"/> <penalty w="0" p="0"/>

Loading…
Cancel
Save