Browse Source

Reverted changes made in revision 796809 (manual merge of clean-up changes made in the ChangingIPDHack branch). Those changes will be re-applied when merging the branch back to Trunk with svn merge --reintegrate (if everything goes well...)


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@808135 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Vincent Hennebert 14 years ago
parent
commit
9520407736

+ 8
- 0
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java View File

@@ -290,6 +290,14 @@ public abstract class AbstractBreaker {
ElementListObserver.observe(elementList, "breaker", null);
}

/**
* Starts the page breaking process.
* @param flowBPD the constant available block-progression-dimension (used for every part)
*/
public void doLayout(int flowBPD) {
doLayout(flowBPD, false);
}

/**
* Starts the page breaking process.
* @param flowBPD the constant available block-progression-dimension (used for every part)

+ 7
- 7
src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java View File

@@ -47,22 +47,22 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
private static Log log = LogFactory.getLog(AbstractLayoutManager.class);

/** Parent LayoutManager for this LayoutManager */
protected LayoutManager parentLM;
protected LayoutManager parentLM = null;
/** List of child LayoutManagers */
protected List childLMs;
protected List childLMs = null;
/** Iterator for child LayoutManagers */
protected ListIterator fobjIter;
protected ListIterator fobjIter = null;
/** Marker map for markers related to this LayoutManager */
private Map markers;
private Map markers = null;

/** True if this LayoutManager has handled all of its content. */
private boolean isFinished;
private boolean isFinished = false;

/** child LM during getNextKnuthElement phase */
protected LayoutManager curChildLM;
protected LayoutManager curChildLM = null;

/** child LM iterator during getNextKnuthElement phase */
protected ListIterator childLMiter;
protected ListIterator childLMiter = null;

private int lastGeneratedPosition = -1;
private int smallestPosNumberChecked = Integer.MAX_VALUE;

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

@@ -117,7 +117,7 @@ public class AreaAdditionUtil {
// set space after for each LM, in order to implement
// display-align = distribute
lc.setSpaceAfter(layoutContext.getSpaceAfter());
lc.setStackLimitBP(layoutContext.getStackLimitBP());
lc.setStackLimitsFrom(layoutContext);
childLM.addAreas(childPosIter, lc);
}


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

@@ -67,6 +67,9 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
private MinOptMax effSpaceBefore;
private MinOptMax effSpaceAfter;

/** The list of child BreakPoss instances. */
protected List childBreaks = new java.util.ArrayList();

/**
* Creates a new BlockLayoutManager.
* @param inBlock the block FO object to create the layout manager for.
@@ -246,8 +249,8 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// and put them in a new list;
LinkedList positionList = new LinkedList();
Position pos;
boolean spaceBefore = false;
boolean spaceAfter = false;
boolean bSpaceBefore = false;
boolean bSpaceAfter = false;
Position firstPos = null;
Position lastPos = null;
while (parentIter.hasNext()) {
@@ -270,11 +273,11 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// this means the space was not discarded
if (positionList.size() == 0) {
// pos was in the element representing space-before
spaceBefore = true;
bSpaceBefore = true;
//log.trace(" space before");
} else {
// pos was in the element representing space-after
spaceAfter = true;
bSpaceAfter = true;
//log.trace(" space-after");
}
} else if (innerPosition.getLM() == this
@@ -299,7 +302,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// the Positions in positionList were inside the elements
// created by the LineLM
childPosIter = new StackingIter(positionList.listIterator());
} else {
} else {
// the Positions in positionList were inside the elements
// created by the BlockLM in the createUnitElements() method
//if (((Position) positionList.getLast()) instanceof
@@ -338,7 +341,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// + " spacing");
// add space before and / or after the paragraph
// to reach a multiple of bpUnit
if (spaceBefore && spaceAfter) {
if (bSpaceBefore && bSpaceAfter) {
foSpaceBefore = new SpaceVal(getBlockFO()
.getCommonMarginBlock().spaceBefore, this).getSpace();
foSpaceAfter = new SpaceVal(getBlockFO()
@@ -351,7 +354,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
+ foSpaceBefore.min
+ foSpaceAfter.min)
* bpUnit - splitLength - adjustedSpaceBefore;
} else if (spaceBefore) {
} else if (bSpaceBefore) {
adjustedSpaceBefore = neededUnits(splitLength
+ foSpaceBefore.min)
* bpUnit - splitLength;

+ 132
- 81
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -54,26 +54,31 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
*/
private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class);

protected BlockParent parentArea;
/**
* Reference to FO whose areas it's managing or to the traits
* of the FO.
*/
//protected LayoutManager curChildLM = null; AbstractLayoutManager also defines this!
protected BlockParent parentArea = null;

/** Value of the block-progression-unit (non-standard property) */
protected int bpUnit;
protected int bpUnit = 0;
/** space-before value adjusted for block-progression-unit handling */
protected int adjustedSpaceBefore;
protected int adjustedSpaceBefore = 0;
/** space-after value adjusted for block-progression-unit handling */
protected int adjustedSpaceAfter;
protected int adjustedSpaceAfter = 0;
/** Only used to store the original list when createUnitElements is called */
protected List storedList;
protected List storedList = null;
/** Indicates whether break before has been served or not */
protected boolean breakBeforeServed;
protected boolean breakBeforeServed = false;
/** Indicates whether the first visible mark has been returned by this LM, yet */
protected boolean firstVisibleMarkServed;
protected boolean firstVisibleMarkServed = false;
/** Reference IPD available */
protected int referenceIPD;
protected int referenceIPD = 0;
/** the effective start-indent value */
protected int startIndent;
protected int startIndent = 0;
/** the effective end-indent value */
protected int endIndent;
protected int endIndent = 0;
/**
* Holds the (one-time use) fo:block space-before
* and -after properties. Large fo:blocks are split
@@ -83,13 +88,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
* Block and space-after at the end of the last Block
* used in rendering the fo:block.
*/
protected MinOptMax foSpaceBefore;
protected MinOptMax foSpaceBefore = null;
/** see foSpaceBefore */
protected MinOptMax foSpaceAfter;
protected MinOptMax foSpaceAfter = null;

private Position auxiliaryPosition;

private int contentAreaIPD;
private int contentAreaIPD = 0;

/**
* @param node the fo this LM deals with
@@ -243,27 +248,38 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager

/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
//log.debug("BLM.getNextKnuthElements> keep-together = "
// + layoutProps.keepTogether.getType());
//log.debug(" keep-with-previous = " +
// layoutProps.keepWithPrevious.getType());
//log.debug(" keep-with-next = " +
// layoutProps.keepWithNext.getType());
BlockLevelLayoutManager curLM; // currently active LM
BlockLevelLayoutManager prevLM = null; // previously active LM

referenceIPD = context.getRefIPD();

updateContentAreaIPDwithOverconstrainedAdjust();

List returnedList = null;
List contentList = new LinkedList();
List elements = new LinkedList();
List returnList = new LinkedList();

if (!breakBeforeServed) {
breakBeforeServed = true;
if (!context.suppressBreakBefore()) {
if (addKnuthElementsForBreakBefore(elements, context)) {
return elements;
if (addKnuthElementsForBreakBefore(returnList, context)) {
return returnList;
}
}
}

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

addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
firstVisibleMarkServed = true;

//Spaces, border and padding to be repeated at each break
@@ -272,107 +288,142 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
//Used to indicate a special break-after case when all content has already been generated.
BreakElement forcedBreakAfterLast = null;

LayoutManager currentChildLM;
while ((currentChildLM = (LayoutManager) getChildLM()) != null) {
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
childLC.copyPendingMarksFrom(context);
if (curLM instanceof LineLayoutManager) {
// curLM is a LineLayoutManager
// set stackLimit for lines (stack limit is now i-p-direction, not b-p-direction!)
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setStackLimitIP(new MinOptMax(getContentAreaIPD()));
childLC.setRefIPD(getContentAreaIPD());
} else {
// curLM is a ?
//childLC.setStackLimit(MinOptMax.subtract(context
// .getStackLimit(), stackSize));
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(referenceIPD);
}
if (curLM == this.childLMs.get(0)) {
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
//Handled already by the parent (break collapsing, see above)
}

List childrenElements = getNextChildElements(currentChildLM, context, childLC,
alignment);

if (contentList.isEmpty()) {
// get elements from curLM
returnedList = curLM.getNextKnuthElements(childLC, alignment);
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
//Propagate keep-with-previous up from the first child
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending();
}
if (childrenElements != null && !childrenElements.isEmpty()) {
if (!contentList.isEmpty()
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) {
if (returnedList != null
&& returnedList.size() == 1
&& ((ListElement) returnedList.get(0)).isForcedBreak()) {

if (curLM.isFinished() && !hasNextChildLM()) {
// a descendant of this block has break-before
forcedBreakAfterLast = (BreakElement) returnedList.get(0);
context.clearPendingMarks();
break;
}

if (contentList.isEmpty()) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered and borders/padding are painted.
returnList.add(new KnuthBox(0, notifyPos(new Position(this)), false));
}
// a descendant of this block has break-before
contentList.addAll(returnedList);

/* extension: conversione di tutta la sequenza fin'ora ottenuta */
if (bpUnit > 0) {
storedList = contentList;
contentList = createUnitElements(contentList);
}
/* end of extension */

// "wrap" the Position inside each element
// moving the elements from contentList to returnList
returnedList = new LinkedList();
wrapPositionElements(contentList, returnList);

return returnList;
} else {
if (returnedList == null || returnedList.isEmpty()) {
//Avoid NoSuchElementException below (happens with empty blocks)
continue;
}
if (prevLM != null
&& !ElementListUtils.startsWithForcedBreak(returnedList)) {
// there is a block handled by prevLM before the one
// handled by curLM, and the one handled
// by the current LM does not begin with a break
addInBetweenBreak(contentList, context, childLC);
}
if (childrenElements.size() == 1
&& ElementListUtils.startsWithForcedBreak(childrenElements)) {

if (currentChildLM.isFinished() && !hasNextChildLM()) {
// a descendant of this block has break-before
forcedBreakAfterLast = (BreakElement) childrenElements.get(0);
contentList.addAll(returnedList);
if (ElementListUtils.endsWithForcedBreak(returnedList)) {
// a descendant of this block has break-after
if (curLM.isFinished() && !hasNextChildLM()) {
forcedBreakAfterLast = (BreakElement) ListUtil
.removeLast(contentList);
context.clearPendingMarks();
break;
}

if (contentList.isEmpty()) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered and borders/padding are painted.
elements.add(new KnuthBox(0, notifyPos(new Position(this)), false));
/* extension: conversione di tutta la sequenza fin'ora ottenuta */
if (bpUnit > 0) {
storedList = contentList;
contentList = createUnitElements(contentList);
}
// a descendant of this block has break-before
contentList.addAll(childrenElements);
/* end of extension */

wrapPositionElements(contentList, elements);
returnedList = new LinkedList();
wrapPositionElements(contentList, returnList);

return elements;
} else {
contentList.addAll(childrenElements);
if (ElementListUtils.endsWithForcedBreak(childrenElements)) {
// a descendant of this block has break-after
if (currentChildLM.isFinished() && !hasNextChildLM()) {
forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
context.clearPendingMarks();
break;
}

wrapPositionElements(contentList, elements);

return elements;
}
return returnList;
}
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
}
// propagate and clear
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
childLC.clearKeepsPending();
prevLM = curLM;
}

/* Extension: conversione di tutta la sequenza fin'ora ottenuta */
if (bpUnit > 0) {
storedList = contentList;
contentList = createUnitElements(contentList);
}
/* end of extension */

returnedList = new LinkedList();
if (!contentList.isEmpty()) {
wrapPositionElements(contentList, elements);
wrapPositionElements(contentList, returnList);
} else if (forcedBreakAfterLast == null) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered.
elements.add(new KnuthBox(0, notifyPos(new Position(this)), true));
returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true));
}

addKnuthElementsForBorderPaddingAfter(elements, true);
addKnuthElementsForSpaceAfter(elements, alignment);
addKnuthElementsForBorderPaddingAfter(returnList, true);
addKnuthElementsForSpaceAfter(returnList, alignment);

//All child content is processed. Only break-after can occur now, so...
context.clearPendingMarks();
if (forcedBreakAfterLast == null) {
addKnuthElementsForBreakAfter(elements, context);
} else {
addKnuthElementsForBreakAfter(returnList, context);
}

if (forcedBreakAfterLast != null) {
forcedBreakAfterLast.clearPendingMarks();
elements.add(forcedBreakAfterLast);
returnList.add(forcedBreakAfterLast);
}

context.updateKeepWithNextPending(getKeepWithNext());

setFinished(true);

return elements;
}

private List getNextChildElements(LayoutManager childLM, LayoutContext context,
LayoutContext childLC, int alignment) {
childLC.copyPendingMarksFrom(context);
childLC.setStackLimitBP(context.getStackLimitBP());
if (childLM instanceof LineLayoutManager) {
childLC.setRefIPD(getContentAreaIPD());
} else {
childLC.setRefIPD(referenceIPD);
}
if (childLM == this.childLMs.get(0)) {
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
//Handled already by the parent (break collapsing, see above)
}

return childLM.getNextKnuthElements(childLC, alignment);
return returnList;
}

/**

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

@@ -1283,8 +1283,12 @@ public abstract class BreakingAlgorithm {
* @return the width/length in millipoints
*/
protected int getLineWidth(int line) {
assert lineWidth >= 0;
return this.lineWidth;
if (this.lineWidth < 0) {
throw new IllegalStateException("lineWidth must be set"
+ (this.lineWidth != 0 ? " and positive, but it is: " + this.lineWidth : ""));
} else {
return this.lineWidth;
}
}

/** @return the constant line/part width or -1 if there is no such value */

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

@@ -29,6 +29,8 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.WrapperLayoutManager;

/**
* LayoutManager for an fo:flow object.
@@ -62,89 +64,110 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {

List elements = new LinkedList();
// set layout dimensions
int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
int flowBPD = getCurrentPV().getBodyRegion().getBPD();

LayoutManager currentChildLM;
while ((currentChildLM = getChildLM()) != null) {
if (handleSpanChange(currentChildLM, elements, context)) {
SpaceResolver.resolveElementList(elements);
return elements;
// currently active LM
LayoutManager curLM;
List returnedList;
List returnList = new LinkedList();

while ((curLM = getChildLM()) != null) {
if (!(curLM instanceof WrapperLayoutManager)
&& curLM instanceof InlineLevelLayoutManager) {
log.error("inline area not allowed under flow - ignoring");
curLM.setFinished(true);
continue;
}

LayoutContext childLC = new LayoutContext(0);
List childrenElements = getNextChildElements(currentChildLM, context, childLC,
alignment);
if (elements.isEmpty()) {
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
int span = EN_NONE;
int disableColumnBalancing = EN_FALSE;
if (curLM instanceof BlockLayoutManager) {
span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO()
.getDisableColumnBalancing();
} else if (curLM instanceof BlockContainerLayoutManager) {
span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO()
.getDisableColumnBalancing();
}
if (!elements.isEmpty()
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) {
addInBetweenBreak(elements, context, childLC);

int currentSpan = context.getCurrentSpan();
if (currentSpan != span) {
if (span == EN_ALL) {
context.setDisableColumnBalancing(disableColumnBalancing);
}
log.debug("span change from " + currentSpan + " to " + span);
context.signalSpanChange(span);
SpaceResolver.resolveElementList(returnList);
return returnList;
}
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());

elements.addAll(childrenElements);
// Set up a LayoutContext
//MinOptMax bpd = context.getStackLimit();

if (ElementListUtils.endsWithForcedBreak(elements)) {
// a descendant of this flow has break-before or break-after
if (currentChildLM.isFinished() && !hasNextChildLM()) {
setFinished(true);
}
SpaceResolver.resolveElementList(elements);
return elements;
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());

// get elements from curLM
returnedList = curLM.getNextKnuthElements(childLC, alignment);
//log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
childLC.clearKeepWithPreviousPending();
}
}

SpaceResolver.resolveElementList(elements);
setFinished(true);
// "wrap" the Position inside each element
List tempList = returnedList;
returnedList = new LinkedList();
wrapPositionElements(tempList, returnedList);

if (returnedList.size() == 1
&& ElementListUtils.endsWithForcedBreak(returnedList)) {
// a descendant of this flow has break-before
returnList.addAll(returnedList);
SpaceResolver.resolveElementList(returnList);
return returnList;
} else if (returnedList.size() > 0) {
if (returnList.size() > 0
&& !ElementListUtils.startsWithForcedBreak(returnedList)) {
addInBetweenBreak(returnList, context, childLC);
}
returnList.addAll(returnedList);
if (ElementListUtils.endsWithForcedBreak(returnList)) {
if (curLM.isFinished() && !hasNextChildLM()) {
//If the layout manager is finished at this point, the pending
//marks become irrelevant.
childLC.clearPendingMarks();
//setFinished(true);
break;
}
// a descendant of this flow has break-after
SpaceResolver.resolveElementList(returnList);
return returnList;
}
}

assert !elements.isEmpty();
return elements;
}
//Propagate and clear
context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
childLC.clearKeepWithNextPending();

private boolean handleSpanChange(LayoutManager childLM, List elements, LayoutContext context) {
int span = EN_NONE;
int disableColumnBalancing = EN_FALSE;
if (childLM instanceof BlockLayoutManager) {
span = ((BlockLayoutManager)childLM).getBlockFO().getSpan();
disableColumnBalancing = ((BlockLayoutManager) childLM).getBlockFO()
.getDisableColumnBalancing();
} else if (childLM instanceof BlockContainerLayoutManager) {
span = ((BlockContainerLayoutManager)childLM).getBlockContainerFO().getSpan();
disableColumnBalancing = ((BlockContainerLayoutManager) childLM).getBlockContainerFO()
.getDisableColumnBalancing();
context.updateKeepWithNextPending(getKeepWithNext());
}

int currentSpan = context.getCurrentSpan();
if (currentSpan != span) {
if (span == EN_ALL) {
context.setDisableColumnBalancing(disableColumnBalancing);
}
log.debug("span change from " + currentSpan + " to " + span);
context.signalSpanChange(span);
return true;
SpaceResolver.resolveElementList(returnList);
setFinished(true);

if (returnList.size() > 0) {
return returnList;
} else {
return false;
return null;
}
}

private List getNextChildElements(LayoutManager childLM, LayoutContext context,
LayoutContext childLC, int alignment) {
childLC.setStackLimitBP(context.getStackLimitBP());
childLC.setRefIPD(context.getRefIPD());
childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());

// get elements from curLM
List childrenElements = childLM.getNextKnuthElements(childLC, alignment);
assert !childrenElements.isEmpty();

// "wrap" the Position inside each element
List tempList = childrenElements;
childrenElements = new LinkedList();
wrapPositionElements(tempList, childrenElements);
return childrenElements;
}

/**
* {@inheritDoc}
*/

+ 12
- 4
src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java View File

@@ -57,12 +57,16 @@ public class InlineKnuthSequence extends KnuthSequence {
return true;
}

/** {@inheritDoc} */
/* (non-Javadoc)
* {@inheritDoc}
*/
public boolean canAppendSequence(KnuthSequence sequence) {
return sequence.isInlineSequence() && !isClosed;
}

/** {@inheritDoc} */
/* (non-Javadoc)
* {@inheritDoc}
*/
public boolean appendSequence(KnuthSequence sequence) {
if (!canAppendSequence(sequence)) {
return false;
@@ -79,14 +83,18 @@ public class InlineKnuthSequence extends KnuthSequence {
return true;
}

/** {@inheritDoc} */
/* (non-Javadoc)
* {@inheritDoc}
*/
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
return appendSequence(sequence);
}


/** {@inheritDoc} */
/* (non-Javadoc)
* {@inheritDoc}
*/
public KnuthSequence endSequence() {
if (!isClosed) {
add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));

+ 38
- 1
src/java/org/apache/fop/layoutmgr/LayoutContext.java View File

@@ -78,6 +78,15 @@ public class LayoutContext {
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimitBP;
/**
* Total available stacking dimension for a "galley-level" layout
* manager in inline-progression-direction. It is passed by the
* parent LM. For LineLM, the block LM determines this based on
* indent properties.
* These LM <b>may</b> wish to pass this information down to lower
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimitIP;

/** to keep track of spanning in multi-column layout */
private int currentSpan = Constants.NOT_SET;
@@ -149,7 +158,7 @@ public class LayoutContext {
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
this.writingMode = parentLC.writingMode;
setStackLimitBP(parentLC.getStackLimitBP());
setStackLimitsFrom(parentLC);
this.leadingSpace = parentLC.leadingSpace; //???
this.trailingSpace = parentLC.trailingSpace; //???
this.hyphContext = parentLC.hyphContext;
@@ -174,6 +183,7 @@ public class LayoutContext {
this.flags = flags;
this.refIPD = 0;
stackLimitBP = new MinOptMax(0);
stackLimitIP = new MinOptMax(0);
leadingSpace = null;
trailingSpace = null;
}
@@ -387,6 +397,31 @@ public class LayoutContext {
return stackLimitBP;
}

/**
* Sets the stack limit in inline-progression-dimension.
* @param limit the stack limit
*/
public void setStackLimitIP(MinOptMax limit) {
stackLimitIP = limit;
}

/**
* Returns the stack limit in inline-progression-dimension.
* @return the stack limit
*/
public MinOptMax getStackLimitIP() {
return stackLimitIP;
}

/**
* Sets (Copies) the stack limits in both directions from another layout context.
* @param context the layout context to take the values from
*/
public void setStackLimitsFrom(LayoutContext context) {
setStackLimitBP(context.getStackLimitBP());
setStackLimitIP(context.getStackLimitIP());
}

/**
* Sets the inline-progression-dimension of the nearest ancestor reference area.
*/
@@ -627,6 +662,8 @@ public class LayoutContext {
return "Layout Context:"
+ "\nStack Limit BPD: \t"
+ (getStackLimitBP() == null ? "null" : getStackLimitBP().toString())
+ "\nStack Limit IPD: \t"
+ (getStackLimitIP() == null ? "null" : getStackLimitIP().toString())
+ "\nTrailing Space: \t"
+ (getTrailingSpace() == null ? "null" : getTrailingSpace().toString())
+ "\nLeading Space: \t"

+ 3
- 3
src/java/org/apache/fop/layoutmgr/LeafPosition.java View File

@@ -21,15 +21,15 @@ package org.apache.fop.layoutmgr;

public class LeafPosition extends Position {

private int leafPos;
private int iLeafPos;

public LeafPosition(LayoutManager lm, int pos) {
super(lm);
leafPos = pos;
iLeafPos = pos;
}

public int getLeafPos() {
return leafPos;
return iLeafPos;
}

public boolean generatesAreas() {

+ 0
- 8
src/java/org/apache/fop/layoutmgr/PageBreaker.java View File

@@ -77,14 +77,6 @@ public class PageBreaker extends AbstractBreaker {
return pslm.getPageProvider();
}

/**
* Starts the page breaking process.
* @param flowBPD the constant available block-progression-dimension (used for every part)
*/
void doLayout(int flowBPD) {
doLayout(flowBPD, false);
}

/** {@inheritDoc} */
protected PageBreakingLayoutListener createLayoutListener() {
return new PageBreakingLayoutListener() {

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

@@ -21,6 +21,10 @@ package org.apache.fop.layoutmgr;

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

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

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
@@ -31,7 +35,10 @@ import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.SideRegion;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener;
import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.TextLayoutManager;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.util.ListUtil;

/**
* LayoutManager for an fo:flow object.
@@ -41,6 +48,11 @@ import org.apache.fop.layoutmgr.inline.TextLayoutManager;
*/
public class StaticContentLayoutManager extends BlockStackingLayoutManager {

/**
* logging instance
*/
private static Log log = LogFactory.getLog(StaticContentLayoutManager.class);

private RegionReference targetRegion;
private Block targetBlock;
private SideRegion regionFO;
@@ -77,7 +89,96 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {

/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
throw new IllegalStateException();
if (true) {
throw new UnsupportedOperationException(
"Shouldn't this method be emptied because it's never called at all?");
}
//TODO Empty this method?!?
// set layout dimensions
setContentAreaIPD(context.getRefIPD());
setContentAreaBPD(context.getStackLimitBP().opt);

//TODO Copied from elsewhere. May be worthwhile to factor out the common parts.
// currently active LM
BlockLevelLayoutManager curLM;
BlockLevelLayoutManager prevLM = null;
MinOptMax stackSize = new MinOptMax();
List returnedList;
List returnList = new LinkedList();

while ((curLM = ((BlockLevelLayoutManager) getChildLM())) != null) {
if (curLM instanceof InlineLevelLayoutManager) {
log.error("inline area not allowed under flow - ignoring");
curLM.setFinished(true);
continue;
}

// Set up a LayoutContext
MinOptMax bpd = context.getStackLimitBP();

LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimitBP(MinOptMax.subtract(bpd, stackSize));
childLC.setRefIPD(context.getRefIPD());

// get elements from curLM
returnedList = curLM.getNextKnuthElements(childLC, alignment);
//log.debug("FLM.getNextKnuthElements> returnedList.size() = "
// + returnedList.size());

// "wrap" the Position inside each element
List tempList = returnedList;
KnuthElement tempElement;
returnedList = new LinkedList();
ListIterator listIter = tempList.listIterator();
while (listIter.hasNext()) {
tempElement = (KnuthElement)listIter.next();
tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
returnedList.add(tempElement);
}

if (returnedList.size() == 1
&& ((KnuthElement)returnedList.get(0)).isPenalty()
&& ((KnuthPenalty)returnedList.get(0)).getP() == -KnuthElement.INFINITE) {
// a descendant of this flow has break-before
returnList.addAll(returnedList);
return returnList;
} else {
if (!returnList.isEmpty()) {
// there is a block before this one
if (prevLM.mustKeepWithNext()
|| curLM.mustKeepWithPrevious()) {
// add an infinite penalty to forbid a break between blocks
returnList.add(new KnuthPenalty(0,
KnuthElement.INFINITE, false,
new Position(this), false));
} else if (!((KnuthElement) ListUtil.getLast(returnList))
.isGlue()) {
// add a null penalty to allow a break between blocks
returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
}
}
/*LF*/ if (!returnedList.isEmpty()) { // controllare!
returnList.addAll(returnedList);
final KnuthElement last = (KnuthElement) ListUtil
.getLast(returnedList);
if (last.isPenalty()
&& ((KnuthPenalty) last).getP() == -KnuthElement.INFINITE) {
// a descendant of this flow has break-after
/*LF*/ //log.debug("FLM - break after!!");
return returnList;
}
/*LF*/ }
}
prevLM = curLM;
}

setFinished(true);

if (returnList.isEmpty()) {
return null;
} else {
return returnList;
}
}

/**

+ 7
- 3
src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java View File

@@ -27,7 +27,6 @@ import java.util.ListIterator;

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

import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
@@ -44,6 +43,7 @@ import org.apache.fop.layoutmgr.PageSequenceLayoutManager;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.traits.MinOptMax;

/**
* Content Layout Manager.
@@ -111,6 +111,8 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
LayoutContext childLC = new LayoutContext(LayoutContext.NEW_AREA);
childLC.setLeadingSpace(new SpaceSpecifier(false));
childLC.setTrailingSpace(new SpaceSpecifier(false));
// set stackLimit for lines
childLC.setStackLimitIP(new MinOptMax(ipd));
childLC.setRefIPD(ipd);

int lineHeight = 14000;
@@ -127,7 +129,8 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager

stackSize = 0;

List contentList = getNextKnuthElements(childLC, Constants.EN_START);
List contentList =
getNextKnuthElements(childLC, Constants.EN_START);
ListIterator contentIter = contentList.listIterator();
while (contentIter.hasNext()) {
KnuthElement element = (KnuthElement) contentIter.next();
@@ -146,7 +149,8 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
lc.setLeadingSpace(new SpaceSpecifier(false));
lc.setTrailingSpace(new SpaceSpecifier(false));
KnuthPossPosIter contentPosIter = new KnuthPossPosIter(contentList, 0, contentList.size());
KnuthPossPosIter contentPosIter =
new KnuthPossPosIter(contentList, 0, contentList.size());
curLM.addAreas(contentPosIter, lc);
}


+ 10
- 0
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java View File

@@ -248,6 +248,8 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
List returnList = new LinkedList();
KnuthSequence lastSequence = null;

SpaceSpecifier leadingSpace = context.getLeadingSpace();

if (fobj instanceof Title) {
alignmentContext = new AlignmentContext(font,
lineHeight.getOptimum(this).getLength().getValue(this),
@@ -272,6 +274,14 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
if (getSpaceStart() != null) {
context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this));
}

// Check for "fence"
if (hasLeadingFence(!context.isFirstArea())) {
// Reset leading space sequence for child areas
leadingSpace = new SpaceSpecifier(false);
}
// Reset state variables
clearPrevIPD(); // Clear stored prev content dimensions
}

StringBuffer trace = new StringBuffer("InlineLM:");

+ 29
- 3
src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java View File

@@ -19,13 +19,12 @@

package org.apache.fop.layoutmgr.inline;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.HashMap;

import org.apache.fop.area.Area;
import org.apache.fop.area.inline.Space;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.AbstractLayoutManager;
@@ -35,6 +34,8 @@ import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.area.Area;
import org.apache.fop.area.inline.Space;
import org.apache.fop.traits.MinOptMax;

/**
@@ -61,6 +62,12 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
}
}


/**
* Size of any start or end borders and padding.
*/
private MinOptMax allocIPD = new MinOptMax(0);

/**
* Size of border and padding in BPD (ie, before and after).
*/
@@ -71,6 +78,9 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
/** The child layout context */
protected LayoutContext childLC;

/** Used to store previous content IPD for each child LM. */
private HashMap hmPrevIPD = new HashMap();

/**
* Create an inline stacking layout manager.
* This is used for fo's that create areas that
@@ -138,6 +148,22 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
return null;
}

/**
* TODO: Explain this method
* @param lm ???
* @return ???
*/
protected MinOptMax getPrevIPD(LayoutManager lm) {
return (MinOptMax) hmPrevIPD.get(lm);
}

/**
* Clear the previous IPD calculation.
*/
protected void clearPrevIPD() {
hmPrevIPD.clear();
}

/**
* Returns the current area.
* @return the current area

+ 353
- 156
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

@@ -116,8 +116,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* inline break positions.
*/
private static class LineBreakPosition extends LeafPosition {
private int parIndex; // index of the Paragraph this Position refers to
private int startIndex; //index of the first element this Position refers to
private int iParIndex; // index of the Paragraph this Position refers to
private int iStartIndex; //index of the first element this Position refers to
private int availableShrink;
private int availableStretch;
private int difference;
@@ -130,16 +130,16 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private int spaceAfter;
private int baseline;

LineBreakPosition(LayoutManager lm, int index, int startIndex, int breakIndex,
LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex,
int shrink, int stretch, int diff,
double ipdA, double adjust, int ind,
int lh, int lw, int sb, int sa, int bl) {
super(lm, breakIndex);
super(lm, iBreakIndex);
availableShrink = shrink;
availableStretch = stretch;
difference = diff;
parIndex = index;
this.startIndex = startIndex;
iParIndex = index;
this.iStartIndex = iStartIndex;
ipdAdjust = ipdA;
dAdjust = adjust;
startIndent = ind;
@@ -167,13 +167,18 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private Length lineHeight;
private int lead;
private int follow;
private AlignmentContext alignmentContext;
private AlignmentContext alignmentContext = null;

private List knuthParagraphs;
private List knuthParagraphs = null;
private int iReturnedLBP = 0;

// parameters of Knuth's algorithm:
// penalty value for flagged penalties
private int flaggedPenalty = 50;

private LineLayoutPossibilities lineLayouts;
private List lineLayoutsList;
private int ipd = 0;
private int iLineWidth = 0;

/**
* this constant is used to create elements when text-align is center:
@@ -233,7 +238,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
lineFiller = new MinOptMax(lastLineEndIndent,
lastLineEndIndent,
layoutManager.ipd);
layoutManager.iLineWidth);
}

// add auxiliary elements at the beginning of the paragraph
@@ -314,9 +319,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private int activePossibility;
private int addedPositions;
private int textIndent;
private int fillerMinWidth;
private int lineHeight;
private int lead;
private int follow;
private int maxDiff;
private static final double MAX_DEMERITS = 10e6;

public LineBreakingAlgorithm (int pageAlign,
@@ -327,17 +334,22 @@ public class LineLayoutManager extends InlineStackingLayoutManager
super(textAlign, textAlignLast, first, false, maxFlagCount);
pageAlignment = pageAlign;
textIndent = indent;
fillerMinWidth = fillerWidth;
lineHeight = lh;
lead = ld;
follow = fl;
thisLLM = llm;
activePossibility = -1;
maxDiff = fobj.getWidows() >= fobj.getOrphans()
? fobj.getWidows()
: fobj.getOrphans();
}

public void updateData1(int lineCount, double demerits) {
lineLayouts.addPossibility(lineCount, demerits);
if (log.isTraceEnabled()) {
log.trace("Layout possibility in " + lineCount + " lines; break at position:");
if (super.log.isTraceEnabled()) {
super.log.trace(
"Layout possibility in " + lineCount + " lines; break at position:");
}
}

@@ -418,7 +430,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// true if this line contains only zero-height, auxiliary boxes
// and the actual line width is 0; in this case, the line "collapses"
// i.e. the line area will have bpd = 0
boolean bZeroHeightLine = (difference == ipd);
boolean bZeroHeightLine = (difference == iLineWidth);

// if line-stacking-strategy is "font-height", the line height
// is not affected by its content
@@ -474,7 +486,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
firstElementIndex, lastElementIndex,
availableShrink, availableStretch,
difference, ratio, 0, indent,
0, ipd, 0, 0, 0);
0, iLineWidth, 0, 0, 0);
} else {
return new LineBreakPosition(thisLLM,
knuthParagraphs.indexOf(par),
@@ -482,7 +494,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
availableShrink, availableStretch,
difference, ratio, 0, indent,
lineLead + lineFollow,
ipd, spaceBefore, spaceAfter,
iLineWidth, spaceBefore, spaceAfter,
lineLead);
}
}
@@ -566,12 +578,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
FontInfo fi = fobj.getFOEventHandler().getFontInfo();
FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi);
Font fs = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this));
alignmentContext = new AlignmentContext(fs, lineHeight.getValue(this),
context.getWritingMode());
alignmentContext
= new AlignmentContext(fs, lineHeight.getValue(this), context.getWritingMode());
context.setAlignmentContext(alignmentContext);
// Get a break from currently active child LM
// Set up constraints for inline level managers

clearPrevIPD();

//PHASE 1: Create Knuth elements
if (knuthParagraphs == null) {
// it's the first time this method is called
@@ -592,6 +606,34 @@ public class LineLayoutManager extends InlineStackingLayoutManager

//PHASE 2: Create line breaks
return createLineBreaks(context.getBPAlignment(), context);
/*
LineBreakPosition lbp = null;
if (breakpoints == null) {
// find the optimal line breaking points for each paragraph
breakpoints = new ArrayList();
ListIterator paragraphsIterator
= knuthParagraphs.listIterator(knuthParagraphs.size());
Paragraph currPar = null;
while (paragraphsIterator.hasPrevious()) {
currPar = (Paragraph) paragraphsIterator.previous();
findBreakingPoints(currPar, context.getStackLimit().opt);
}
}*/

//PHASE 3: Return lines

/*
// get a break point from the list
lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
if (iReturnedLBP == breakpoints.size()) {
setFinished(true);
}

BreakPoss curLineBP = new BreakPoss(lbp);
curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
return curLineBP;
*/
}

/**
@@ -601,20 +643,22 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private void collectInlineKnuthElements(LayoutContext context) {
LayoutContext inlineLC = new LayoutContext(context);

ipd = context.getRefIPD();
InlineLevelLayoutManager curLM;
List returnedList = null;
iLineWidth = context.getStackLimitIP().opt;

// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
boolean previousIsBox = false;
boolean bPrevWasKnuthBox = false;

StringBuffer trace = new StringBuffer("LineLM:");

Paragraph lastPar = null;

InlineLevelLayoutManager curLM;
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
List inlineElements = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
if (inlineElements == null || inlineElements.size() == 0) {
returnedList = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
if (returnedList == null
|| returnedList.size() == 0) {
/* curLM.getNextKnuthElements() returned null or an empty list;
* this can happen if there is nothing more to layout,
* so just iterate once more to see if there are other children */
@@ -622,7 +666,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}

if (lastPar != null) {
KnuthSequence firstSeq = (KnuthSequence) inlineElements.get(0);
KnuthSequence firstSeq = (KnuthSequence) returnedList.get(0);

// finish last paragraph before a new block sequence
if (!firstSeq.isInlineSequence()) {
@@ -632,7 +676,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (log.isTraceEnabled()) {
trace.append(" ]");
}
previousIsBox = false;
bPrevWasKnuthBox = false;
}

// does the first element of the first paragraph add to an existing word?
@@ -640,24 +684,27 @@ public class LineLayoutManager extends InlineStackingLayoutManager
KnuthElement thisElement;
thisElement = (KnuthElement) firstSeq.get(0);
if (thisElement.isBox() && !thisElement.isAuxiliary()
&& previousIsBox) {
&& bPrevWasKnuthBox) {
lastPar.addALetterSpace();
}
}
}

// loop over the KnuthSequences (and single KnuthElements) in returnedList
ListIterator iter = inlineElements.listIterator();
ListIterator iter = returnedList.listIterator();
while (iter.hasNext()) {
KnuthSequence sequence = (KnuthSequence) iter.next();
// the sequence contains inline Knuth elements
if (sequence.isInlineSequence()) {
// look at the last element
ListElement lastElement = sequence.getLast();
assert lastElement != null;
previousIsBox = lastElement.isBox()
&& !((KnuthElement) lastElement).isAuxiliary()
&& ((KnuthElement) lastElement).getW() != 0;
if (lastElement == null) {
throw new NullPointerException(
"Sequence was empty! lastElement is null");
}
bPrevWasKnuthBox = lastElement.isBox()
&& !((KnuthElement) lastElement).isAuxiliary()
&& ((KnuthElement) lastElement).getW() != 0;

// if last paragraph is open, add the new elements to the paragraph
// else this is the last paragraph
@@ -682,7 +729,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager

// finish last paragraph if it was closed with a linefeed
if (lastElement.isPenalty()
&& ((KnuthPenalty) lastElement).getP() == -KnuthPenalty.INFINITE) {
&& ((KnuthPenalty) lastElement).getP()
== -KnuthPenalty.INFINITE) {
// a penalty item whose value is -inf
// represents a preserved linefeed,
// which forces a line break
@@ -690,7 +738,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (!lastPar.containsBox()) {
//only a forced linefeed on this line
//-> compensate with an auxiliary glue
lastPar.add(new KnuthGlue(ipd, 0, ipd, null, true));
lastPar.add(new KnuthGlue(iLineWidth, 0, iLineWidth, null, true));
}
lastPar.endParagraph();
ElementListObserver.observe(lastPar, "line", null);
@@ -698,7 +746,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (log.isTraceEnabled()) {
trace.append(" ]");
}
previousIsBox = false;
bPrevWasKnuthBox = false;
}
} else { // the sequence is a block sequence
// the positions will be wrapped with this LM in postProcessLineBreaks
@@ -719,6 +767,134 @@ public class LineLayoutManager extends InlineStackingLayoutManager
log.trace(trace);
}

/**
* Find a set of breaking points.
* This method is called only once by getNextBreakPoss, and it
* subsequently calls the other findBreakingPoints() method with
* different parameters, until a set of breaking points is found.
*
* @param par the list of elements that must be parted
* into lines
* @param lineWidth the desired length ot the lines
*/
/*
private void findBreakingPoints(Paragraph par, int lineWidth) {
// maximum adjustment ratio permitted
float maxAdjustment = 1;

// first try
if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
// the first try failed, now try something different
log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
if (hyphenationProperties.hyphenate == Constants.EN_TRUE) {
// consider every hyphenation point as a legal break
findHyphenationPoints(par);
} else {
// try with a higher threshold
maxAdjustment = 5;
}

if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
// the second try failed too, try with a huge threshold;
// if this fails too, use a different algorithm
log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+ (hyphenationProperties.hyphenate == Constants.EN_TRUE ? " and hyphenation" : ""));
maxAdjustment = 20;
if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) {
log.debug("No set of breaking points found, using first-fit algorithm");
}
}
}
}

private boolean findBreakingPoints(Paragraph par, int lineWidth,
double threshold, boolean force) {
KnuthParagraph knuthPara = new KnuthParagraph(par);
int lines = knuthPara.findBreakPoints(lineWidth, threshold, force);
if (lines == 0) {
return false;
}

for (int i = lines-1; i >= 0; i--) {
int line = i+1;
if (log.isTraceEnabled()) {
log.trace("Making line from " + knuthPara.getStart(i) + " to " +
knuthPara.getEnd(i));
}
// compute indent and adjustment ratio, according to
// the value of text-align and text-align-last

int difference = knuthPara.getDifference(i);
if (line == lines) {
difference += par.lineFillerWidth;
}
int textAlign = (line < lines)
? textAlignment : textAlignmentLast;
int indent = (textAlign == EN_CENTER)
? difference / 2
: (textAlign == EN_END) ? difference : 0;
indent += (line == 1 && knuthParagraphs.indexOf(par) == 0)
? textIndent.getValue(this) : 0;
double ratio = (textAlign == EN_JUSTIFY)
? knuthPara.getAdjustRatio(i) : 0;

int start = knuthPara.getStart(i);
int end = knuthPara.getEnd(i);
makeLineBreakPosition(par, start, end, 0, ratio, indent);
}
return true;
}

private void makeLineBreakPosition(Paragraph par,
int firstElementIndex, int lastElementIndex,
int insertIndex, double ratio, int indent) {
// line height calculation

int halfLeading = (lineHeight - lead - follow) / 2;
// height above the main baseline
int lineLead = lead + halfLeading;
// maximum size of top and bottom alignment
int lineFollow = follow + halfLeading;

ListIterator inlineIterator
= par.listIterator(firstElementIndex);
for (int j = firstElementIndex;
j <= lastElementIndex;
j++) {
KnuthElement element = (KnuthElement) inlineIterator.next();
if (element.isBox()) {
KnuthInlineBox box = (KnuthInlineBox)element;
if (box.getLead() > lineLead) {
lineLead = box.getLead();
}
if (box.getTotal() > lineFollow) {
lineFollow = box.getTotal();
}
if (box.getMiddle() > lineLead + middleShift) {
lineLead += box.getMiddle()
- lineLead - middleShift;
}
if (box.getMiddle() > middlefollow - middleShift) {
middlefollow += box.getMiddle()
- middlefollow + middleShift;
}
}
}

if (lineFollow - lineLead > middlefollow) {
middlefollow = lineFollow - lineLead;
}

breakpoints.add(insertIndex,
new LineBreakPosition(this,
knuthParagraphs.indexOf(par),
lastElementIndex ,
ratio, 0, indent,
lineLead + middlefollow,
lineLead));
}*/


/**
* Phase 2 of Knuth algorithm: find optimal break points.
* @param alignment alignment in BP direction of the paragraph
@@ -726,8 +902,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* @return a list of Knuth elements representing broken lines
*/
private List createLineBreaks(int alignment, LayoutContext context) {

// find the optimal line breaking points for each paragraph
ListIterator paragraphsIterator = knuthParagraphs.listIterator(knuthParagraphs.size());
ListIterator paragraphsIterator
= knuthParagraphs.listIterator(knuthParagraphs.size());
lineLayoutsList = new ArrayList(knuthParagraphs.size());
LineLayoutPossibilities llPoss;
while (paragraphsIterator.hasPrevious()) {
@@ -780,7 +958,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
allowedBreaks = BreakingAlgorithm.NO_FLAGGED_PENALTIES;
}
alg.setConstantLineWidth(ipd);
alg.setConstantLineWidth(iLineWidth);
iBPcount = alg.findBreakingPoints(currPar,
maxAdjustment, false, allowedBreaks);
if (iBPcount == 0 || alignment == EN_JUSTIFY) {
@@ -836,26 +1014,26 @@ public class LineLayoutManager extends InlineStackingLayoutManager
alg.resetAlgorithm();
lineLayouts.savePossibilities(true);
// try with shorter lines
int savedLineWidth = ipd;
ipd = (int) (ipd * 0.95);
int savedLineWidth = iLineWidth;
iLineWidth = (int) (iLineWidth * 0.95);
iBPcount = alg.findBreakingPoints(currPar,
maxAdjustment, true, allowedBreaks);
maxAdjustment, true, allowedBreaks);
// use normal lines, when possible
lineLayouts.restorePossibilities();
ipd = savedLineWidth;
iLineWidth = savedLineWidth;
}
if (!lineLayouts.canUseLessLines()) {
alg.resetAlgorithm();
lineLayouts.savePossibilities(true);
// try with longer lines
int savedLineWidth = ipd;
ipd = (int) (ipd * 1.05);
alg.setConstantLineWidth(ipd);
int savedLineWidth = iLineWidth;
iLineWidth = (int) (iLineWidth * 1.05);
alg.setConstantLineWidth(iLineWidth);
iBPcount = alg.findBreakingPoints(currPar,
maxAdjustment, true, allowedBreaks);
// use normal lines, when possible
lineLayouts.restorePossibilities();
ipd = savedLineWidth;
iLineWidth = savedLineWidth;
}
//log.debug("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
//log.debug(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
@@ -937,14 +1115,15 @@ public class LineLayoutManager extends InlineStackingLayoutManager
while (elementIterator.nextIndex() <= endIndex) {
KnuthElement element = (KnuthElement) elementIterator.next();
if (element instanceof KnuthInlineBox
&& ((KnuthInlineBox) element).isAnchor()) {
&& ((KnuthInlineBox) element).isAnchor()) {
footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
} else if (element instanceof KnuthBlockBox) {
footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
}
}
startIndex = endIndex + 1;
LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i);
LineBreakPosition lbp
= (LineBreakPosition) llPoss.getChosenPosition(i);
returnList.add(new KnuthBlockBox
(lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
footnoteList, lbp, false));
@@ -1418,7 +1597,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
Position pos = (Position) parentIter.next();
boolean isLastPosition = !parentIter.hasNext();
if (pos instanceof LineBreakPosition) {
addInlineArea(context, (LineBreakPosition) pos, isLastPosition);
addInlineArea(context, pos, isLastPosition);
} else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) {
addBlockArea(context, pos, isLastPosition);
} else {
@@ -1438,129 +1617,147 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* @param pos the position for which the line is generated
* @param isLastPosition true if this is the last position of this LM
*/
private void addInlineArea(LayoutContext context, LineBreakPosition lbp,
boolean isLastPosition) {
// the TLM which created the last KnuthElement in this line
LayoutManager lastLM = null;

KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(lbp.parIndex);
int startElementIndex = lbp.startIndex;
int endElementIndex = lbp.getLeafPos();

LineArea lineArea = new LineArea(
(lbp.getLeafPos() < seq.size() - 1 ? textAlignment : textAlignmentLast),
lbp.difference, lbp.availableStretch, lbp.availableShrink);
if (lbp.startIndent != 0) {
lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent));
}
lineArea.setBPD(lbp.lineHeight);
lineArea.setIPD(lbp.lineWidth);
lineArea.addTrait(Trait.SPACE_BEFORE, new Integer(lbp.spaceBefore));
lineArea.addTrait(Trait.SPACE_AFTER, new Integer(lbp.spaceAfter));
alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);

if (seq instanceof Paragraph) {
Paragraph currPar = (Paragraph) seq;
// ignore the first elements added by the LineLayoutManager
startElementIndex += (startElementIndex == 0) ? currPar.ignoreAtStart : 0;

// if this is the last line area that for this paragraph,
// ignore the last elements added by the LineLayoutManager and
// subtract the last-line-end-indent from the area ipd
if (endElementIndex == (currPar.size() - 1)) {
endElementIndex -= currPar.ignoreAtEnd;
lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this));
private void addInlineArea(LayoutContext context, Position pos, boolean isLastPosition) {
ListIterator seqIterator = null;
KnuthElement tempElement = null;
// the TLM which created the last KnuthElement in this line
LayoutManager lastLM = null;

LineBreakPosition lbp = (LineBreakPosition) pos;
int iCurrParIndex;
iCurrParIndex = lbp.iParIndex;
KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex);
int iStartElement = lbp.iStartIndex;
int iEndElement = lbp.getLeafPos();

LineArea lineArea
= new LineArea((lbp.getLeafPos() < seq.size() - 1
? textAlignment : textAlignmentLast),
lbp.difference, lbp.availableStretch, lbp.availableShrink);
if (lbp.startIndent != 0) {
lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent));
}
lineArea.setBPD(lbp.lineHeight);
lineArea.setIPD(lbp.lineWidth);
lineArea.addTrait(Trait.SPACE_BEFORE, new Integer(lbp.spaceBefore));
lineArea.addTrait(Trait.SPACE_AFTER, new Integer(lbp.spaceAfter));
alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);

if (seq instanceof Paragraph) {
Paragraph currPar = (Paragraph) seq;
// ignore the first elements added by the LineLayoutManager
iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;

// if this is the last line area that for this paragraph,
// ignore the last elements added by the LineLayoutManager and
// subtract the last-line-end-indent from the area ipd
if (iEndElement == (currPar.size() - 1)) {
iEndElement -= currPar.ignoreAtEnd;
lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this));
}
}
}

// Remove trailing spaces if allowed so
if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
// Remove trailing spaces if allowed so
if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
|| whiteSpaceTreament == EN_IGNORE
|| whiteSpaceTreament == EN_IGNORE_IF_BEFORE_LINEFEED) {
// ignore the last element in the line if it is a KnuthGlue object
ListIterator seqIterator = seq.listIterator(endElementIndex);
KnuthElement lastElement = (KnuthElement) seqIterator.next();
lastLM = lastElement.getLayoutManager();
if (lastElement.isGlue()) {
endElementIndex--;
// this returns the same KnuthElement
seqIterator.previous();
if (seqIterator.hasPrevious()) {
lastLM = ((KnuthElement) seqIterator.previous()).getLayoutManager();
// ignore the last element in the line if it is a KnuthGlue object
seqIterator = seq.listIterator(iEndElement);
tempElement = (KnuthElement) seqIterator.next();
if (tempElement.isGlue()) {
iEndElement--;
// this returns the same KnuthElement
seqIterator.previous();
if (seqIterator.hasPrevious()) {
tempElement = (KnuthElement) seqIterator.previous();
} else {
tempElement = null;
}
}
if (tempElement != null) {
lastLM = tempElement.getLayoutManager();
}
}
}

// Remove leading spaces if allowed so
if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
// Remove leading spaces if allowed so
if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
|| whiteSpaceTreament == EN_IGNORE
|| whiteSpaceTreament == EN_IGNORE_IF_AFTER_LINEFEED) {
// ignore KnuthGlue and KnuthPenalty objects
// at the beginning of the line
ListIterator seqIterator = seq.listIterator(startElementIndex);
while (seqIterator.hasNext() && !((KnuthElement) seqIterator.next()).isBox()) {
startElementIndex++;
// ignore KnuthGlue and KnuthPenalty objects
// at the beginning of the line
seqIterator = seq.listIterator(iStartElement);
tempElement = (KnuthElement) seqIterator.next();
while (!tempElement.isBox() && seqIterator.hasNext()) {
tempElement = (KnuthElement) seqIterator.next();
iStartElement++;
}
}
}
// Add the inline areas to lineArea
PositionIterator inlinePosIter = new KnuthPossPosIter(seq, startElementIndex,
endElementIndex + 1);

LayoutContext lc = new LayoutContext(0);
lc.setAlignmentContext(alignmentContext);
lc.setSpaceAdjust(lbp.dAdjust);
lc.setIPDAdjust(lbp.ipdAdjust);
lc.setLeadingSpace(new SpaceSpecifier(true));
lc.setTrailingSpace(new SpaceSpecifier(false));
lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);

/*
* extension (not in the XSL FO recommendation): if the left and right margins
* have been optimized, recompute indents and / or adjust ratio, according
* to the paragraph horizontal alignment
*/
if (false && textAlignment == EN_JUSTIFY) {
// re-compute space adjust ratio
int updatedDifference = context.getRefIPD()
- lbp.lineWidth + lbp.difference;
double updatedRatio = 0.0;
if (updatedDifference > 0) {
updatedRatio = (float) updatedDifference / lbp.availableStretch;
} else if (updatedDifference < 0) {
updatedRatio = (float) updatedDifference / lbp.availableShrink;
// Add the inline areas to lineArea
PositionIterator inlinePosIter
= new KnuthPossPosIter(seq, iStartElement, iEndElement + 1);

iStartElement = lbp.getLeafPos() + 1;
if (iStartElement == seq.size()) {
// advance to next paragraph
iStartElement = 0;
}
lc.setIPDAdjust(updatedRatio);
//log.debug("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
//log.debug(" old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
} else if (false && textAlignment == EN_CENTER) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getRefIPD() - lbp.lineWidth) / 2;
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
} else if (false && textAlignment == EN_END) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getRefIPD() - lbp.lineWidth);
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
}

setCurrentArea(lineArea);
setChildContext(lc);
LayoutManager childLM;
while ((childLM = inlinePosIter.getNextChildLM()) != null) {
lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
childLM.addAreas(inlinePosIter, lc);
lc.setLeadingSpace(lc.getTrailingSpace());
LayoutContext lc = new LayoutContext(0);
lc.setAlignmentContext(alignmentContext);
lc.setSpaceAdjust(lbp.dAdjust);
lc.setIPDAdjust(lbp.ipdAdjust);
lc.setLeadingSpace(new SpaceSpecifier(true));
lc.setTrailingSpace(new SpaceSpecifier(false));
}
lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);

/*
* extension (not in the XSL FO recommendation): if the left and right margins
* have been optimized, recompute indents and / or adjust ratio, according
* to the paragraph horizontal alignment
*/
if (false && textAlignment == EN_JUSTIFY) {
// re-compute space adjust ratio
int updatedDifference = context.getStackLimitIP().opt
- lbp.lineWidth + lbp.difference;
double updatedRatio = 0.0;
if (updatedDifference > 0) {
updatedRatio = (float) updatedDifference / lbp.availableStretch;
} else if (updatedDifference < 0) {
updatedRatio = (float) updatedDifference / lbp.availableShrink;
}
lc.setIPDAdjust(updatedRatio);
//log.debug("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
//log.debug(" old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
} else if (false && textAlignment == EN_CENTER) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getStackLimitIP().opt - lbp.lineWidth) / 2;
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
} else if (false && textAlignment == EN_END) {
// re-compute indent
int updatedIndent = lbp.startIndent
+ (context.getStackLimitIP().opt - lbp.lineWidth);
lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
}

// if display-align is distribute, add space after
if (context.getSpaceAfter() > 0
&& (!context.isLastArea() || !isLastPosition)) {
lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
}
lineArea.finalise();
parentLM.addChildArea(lineArea);
setCurrentArea(lineArea);
setChildContext(lc);
LayoutManager childLM;
while ((childLM = inlinePosIter.getNextChildLM()) != null) {
lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
childLM.addAreas(inlinePosIter, lc);
lc.setLeadingSpace(lc.getTrailingSpace());
lc.setTrailingSpace(new SpaceSpecifier(false));
}

// when can this be null?
// if display-align is distribute, add space after
if (context.getSpaceAfter() > 0
&& (!context.isLastArea() || !isLastPosition)) {
lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
}
lineArea.finalise();
parentLM.addChildArea(lineArea);
}

/**
@@ -1603,7 +1800,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// set last area flag
blocklc.setFlags(LayoutContext.LAST_AREA,
(context.isLastArea() && childLM == lastLM));
blocklc.setStackLimitBP(context.getStackLimitBP());
blocklc.setStackLimitsFrom(context);
// Add the line areas to Area
childLM.addAreas(childPosIter, blocklc);
blocklc.setLeadingSpace(blocklc.getTrailingSpace());

Loading…
Cancel
Save