git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@808157 13f79535-47bb-0310-9956-ffa450edef68tags/fop-1_0
@@ -19,8 +19,12 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.List; | |||
import java.util.Stack; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.datatypes.LengthBase; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
import org.apache.fop.fo.FObj; | |||
@@ -253,4 +257,20 @@ public abstract class AbstractBaseLayoutManager | |||
return fobj; | |||
} | |||
/** {@inheritDoc} */ | |||
public void reset() { | |||
throw new UnsupportedOperationException("Not implemented"); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRestartable() { | |||
return false; | |||
} | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | |||
Position positionAtIPDChange, LayoutManager restartAtLM) { | |||
throw new UnsupportedOperationException("Not implemented"); | |||
} | |||
} |
@@ -19,6 +19,8 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.Collections; | |||
import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
@@ -27,6 +29,7 @@ import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode; | |||
import org.apache.fop.traits.MinOptMax; | |||
import org.apache.fop.util.ListUtil; | |||
@@ -247,6 +250,11 @@ public abstract class AbstractBreaker { | |||
*/ | |||
protected abstract List getNextKnuthElements(LayoutContext context, int alignment); | |||
protected List getNextKnuthElements(LayoutContext context, int alignment, | |||
Position positionAtIPDChange, LayoutManager restartAtLM) { | |||
throw new UnsupportedOperationException("TODO: implement acceptable fallback"); | |||
} | |||
/** @return true if there's no content that could be handled. */ | |||
public boolean isEmpty() { | |||
return (this.blockLists.isEmpty()); | |||
@@ -290,14 +298,6 @@ 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) | |||
@@ -354,7 +354,6 @@ public abstract class AbstractBreaker { | |||
getPageProvider(), createLayoutListener(), | |||
alignment, alignmentLast, footnoteSeparatorLength, | |||
isPartOverflowRecoveryActivated(), autoHeight, isSinglePartFavored()); | |||
int iOptPageCount; | |||
BlockSequence effectiveList; | |||
if (getCurrentDisplayAlign() == Constants.EN_X_FILL) { | |||
@@ -365,21 +364,107 @@ public abstract class AbstractBreaker { | |||
effectiveList = blockList; | |||
} | |||
//iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true); | |||
alg.setConstantLineWidth(flowBPD); | |||
iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/ | |||
1, true, BreakingAlgorithm.ALL_BREAKS); | |||
log.debug("PLM> iOptPageCount= " + iOptPageCount | |||
+ " pageBreaks.size()= " + alg.getPageBreaks().size()); | |||
int optimalPageCount = alg.findBreakingPoints(effectiveList, 1, true, | |||
BreakingAlgorithm.ALL_BREAKS); | |||
if (alg.ipdChanged()) { | |||
KnuthNode optimalBreak = alg.getBestNodeBeforeIPDChange(); | |||
int positionIndex = optimalBreak.position; | |||
KnuthElement elementAtBreak = alg.getElement(positionIndex); | |||
Position positionAtBreak = elementAtBreak.getPosition(); | |||
if (!(positionAtBreak instanceof SpaceResolver.SpaceHandlingBreakPosition)) { | |||
throw new UnsupportedOperationException( | |||
"Don't know how to restart at position" + positionAtBreak); | |||
} | |||
/* Retrieve the original position wrapped into this space position */ | |||
positionAtBreak = positionAtBreak.getPosition(); | |||
LayoutManager restartAtLM = null; | |||
List firstElements = Collections.EMPTY_LIST; | |||
if (containsNonRestartableLM(positionAtBreak)) { | |||
firstElements = new LinkedList(); | |||
boolean boxFound = false; | |||
Iterator iter = effectiveList.listIterator(++positionIndex); | |||
Position position = null; | |||
while (iter.hasNext() | |||
&& (position == null || containsNonRestartableLM(position))) { | |||
KnuthElement element = (KnuthElement) iter.next(); | |||
positionIndex++; | |||
position = element.getPosition(); | |||
if (element.isBox()) { | |||
boxFound = true; | |||
firstElements.add(element); | |||
} else if (boxFound) { | |||
firstElements.add(element); | |||
} | |||
} | |||
if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) { | |||
/* Retrieve the original position wrapped into this space position */ | |||
positionAtBreak = position.getPosition(); | |||
} | |||
} | |||
if (positionAtBreak.getIndex() == -1) { | |||
/* | |||
* This is an indication that we are between two blocks | |||
* (possibly surrounded by another block), not inside a | |||
* paragraph. | |||
*/ | |||
Position position; | |||
Iterator iter = effectiveList.listIterator(positionIndex + 1); | |||
do { | |||
KnuthElement nextElement = (KnuthElement) iter.next(); | |||
position = nextElement.getPosition(); | |||
} while (position == null | |||
|| position instanceof SpaceResolver.SpaceHandlingPosition | |||
|| position instanceof SpaceResolver.SpaceHandlingBreakPosition | |||
&& position.getPosition().getIndex() == -1); | |||
LayoutManager surroundingLM = positionAtBreak.getLM(); | |||
while (position.getLM() != surroundingLM) { | |||
position = position.getPosition(); | |||
} | |||
restartAtLM = position.getPosition().getLM(); | |||
} | |||
log.trace("IPD changes after page " + optimalPageCount + " at index " | |||
+ optimalBreak.position); | |||
doPhase3(alg, optimalPageCount, blockList, effectiveList); | |||
blockLists.clear(); | |||
blockListIndex = -1; | |||
nextSequenceStartsOn = getNextBlockList(childLC, Constants.EN_COLUMN, | |||
positionAtBreak, restartAtLM, firstElements); | |||
} else { | |||
log.debug("PLM> iOptPageCount= " + optimalPageCount | |||
+ " pageBreaks.size()= " + alg.getPageBreaks().size()); | |||
//*** Phase 3: Add areas *** | |||
doPhase3(alg, iOptPageCount, blockList, effectiveList); | |||
//*** Phase 3: Add areas *** | |||
doPhase3(alg, optimalPageCount, blockList, effectiveList); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* Returns {@code true} if the given position or one of its descendants | |||
* corresponds to a non-restartable LM. | |||
* | |||
* @param position a position | |||
* @return {@code true} if there is a non-restartable LM in the hierarchy | |||
*/ | |||
private boolean containsNonRestartableLM(Position position) { | |||
LayoutManager lm = position.getLM(); | |||
if (lm != null && !lm.isRestartable()) { | |||
return true; | |||
} else { | |||
Position subPosition = position.getPosition(); | |||
if (subPosition == null) { | |||
return false; | |||
} else { | |||
return containsNonRestartableLM(subPosition); | |||
} | |||
} | |||
} | |||
/** | |||
* Phase 3 of Knuth algorithm: Adds the areas | |||
* @param alg PageBreakingAlgorithm instance which determined the breaks | |||
@@ -559,6 +644,7 @@ public abstract class AbstractBreaker { | |||
protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) { | |||
return nextSequenceStartsOn; | |||
} | |||
/** | |||
* Gets the next block list (sequence) and adds it to a list of block lists if it's not empty. | |||
* @param childLC LayoutContext to use | |||
@@ -567,12 +653,38 @@ public abstract class AbstractBreaker { | |||
*/ | |||
protected int getNextBlockList(LayoutContext childLC, | |||
int nextSequenceStartsOn) { | |||
return getNextBlockList(childLC, nextSequenceStartsOn, null, null, null); | |||
} | |||
/** | |||
* Gets the next block list (sequence) and adds it to a list of block lists | |||
* if it's not empty. | |||
* | |||
* @param childLC LayoutContext to use | |||
* @param nextSequenceStartsOn indicates on what page the next sequence | |||
* should start | |||
* @param positionAtIPDChange last element on the part before an IPD change | |||
* @param restartAtLM the layout manager from which to restart, if IPD | |||
* change occurs between two LMs | |||
* @param firstElements elements from non-restartable LMs on the new page | |||
* @return the page on which the next content should appear after a hard | |||
* break | |||
*/ | |||
protected int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn, | |||
Position positionAtIPDChange, LayoutManager restartAtLM, List firstElements) { | |||
updateLayoutContext(childLC); | |||
//Make sure the span change signal is reset | |||
childLC.signalSpanChange(Constants.NOT_SET); | |||
BlockSequence blockList; | |||
List returnedList = getNextKnuthElements(childLC, alignment); | |||
List returnedList; | |||
if (positionAtIPDChange == null) { | |||
returnedList = getNextKnuthElements(childLC, alignment); | |||
} else { | |||
returnedList = getNextKnuthElements(childLC, alignment, positionAtIPDChange, | |||
restartAtLM); | |||
returnedList.addAll(0, firstElements); | |||
} | |||
if (returnedList != null) { | |||
if (returnedList.isEmpty()) { | |||
nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn); |
@@ -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 = null; | |||
protected LayoutManager parentLM; | |||
/** List of child LayoutManagers */ | |||
protected List childLMs = null; | |||
protected List childLMs; | |||
/** Iterator for child LayoutManagers */ | |||
protected ListIterator fobjIter = null; | |||
protected ListIterator fobjIter; | |||
/** Marker map for markers related to this LayoutManager */ | |||
private Map markers = null; | |||
private Map markers; | |||
/** True if this LayoutManager has handled all of its content. */ | |||
private boolean isFinished = false; | |||
private boolean isFinished; | |||
/** child LM during getNextKnuthElement phase */ | |||
protected LayoutManager curChildLM = null; | |||
protected LayoutManager curChildLM; | |||
/** child LM iterator during getNextKnuthElement phase */ | |||
protected ListIterator childLMiter = null; | |||
protected ListIterator childLMiter; | |||
private int lastGeneratedPosition = -1; | |||
private int smallestPosNumberChecked = Integer.MAX_VALUE; | |||
@@ -122,6 +122,14 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
return null; | |||
} | |||
protected void setCurrentChildLM(LayoutManager childLM) { | |||
curChildLM = childLM; | |||
childLMiter = new LMiter(this); | |||
do { | |||
curChildLM = (LayoutManager) childLMiter.next(); | |||
} while (curChildLM != childLM); | |||
} | |||
/** | |||
* Return indication if getChildLM will return another LM. | |||
* @return true if another child LM is still available | |||
@@ -450,4 +458,22 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager | |||
return (super.toString() + (fobj != null ? "[fobj=" + fobj.toString() + "]" : "")); | |||
} | |||
/** {@inheritDoc} */ | |||
public void reset() { | |||
isFinished = false; | |||
curChildLM = null; | |||
childLMiter = new LMiter(this); | |||
/* | |||
* Reset the children LM. Can't rely on childLMiter since it may have | |||
* been set to null in checkEndOfLayout. | |||
*/ | |||
for (LMiter iter = new LMiter(this); iter.hasNext();) { | |||
((LayoutManager) iter.next()).reset(); | |||
} | |||
if (fobj != null) { | |||
markers = fobj.getMarkers(); | |||
} | |||
lastGeneratedPosition = -1; | |||
} | |||
} |
@@ -382,4 +382,9 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void reset() { | |||
throw new IllegalStateException(); | |||
} | |||
} |
@@ -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.setStackLimitsFrom(layoutContext); | |||
lc.setStackLimitBP(layoutContext.getStackLimitBP()); | |||
childLM.addAreas(childPosIter, lc); | |||
} | |||
@@ -24,6 +24,7 @@ import java.awt.geom.Rectangle2D; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Stack; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -397,6 +398,311 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager | |||
return returnList; | |||
} | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | |||
Position restartPosition, LayoutManager restartAtLM) { | |||
resetSpaces(); | |||
if (isAbsoluteOrFixed()) { | |||
return getNextKnuthElementsAbsolute(context, alignment); | |||
} | |||
autoHeight = false; | |||
//boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0); | |||
int maxbpd = context.getStackLimitBP().opt; | |||
int allocBPD; | |||
if (height.getEnum() == EN_AUTO | |||
|| (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) { | |||
//auto height when height="auto" or "if that dimension is not specified explicitly | |||
//(i.e., it depends on content's block-progression-dimension)" (XSL 1.0, 7.14.1) | |||
allocBPD = maxbpd; | |||
autoHeight = true; | |||
if (getBlockContainerFO().getReferenceOrientation() == 0) { | |||
//Cannot easily inline element list when ref-or="180" | |||
inlineElementList = true; | |||
} | |||
} else { | |||
allocBPD = height.getValue(this); //this is the content-height | |||
allocBPD += getBPIndents(); | |||
} | |||
vpContentBPD = allocBPD - getBPIndents(); | |||
referenceIPD = context.getRefIPD(); | |||
if (width.getEnum() == EN_AUTO) { | |||
updateContentAreaIPDwithOverconstrainedAdjust(); | |||
} else { | |||
int contentWidth = width.getValue(this); | |||
updateContentAreaIPDwithOverconstrainedAdjust(contentWidth); | |||
} | |||
double contentRectOffsetX = 0; | |||
contentRectOffsetX += getBlockContainerFO() | |||
.getCommonMarginBlock().startIndent.getValue(this); | |||
double contentRectOffsetY = 0; | |||
contentRectOffsetY += getBlockContainerFO() | |||
.getCommonBorderPaddingBackground().getBorderBeforeWidth(false); | |||
contentRectOffsetY += getBlockContainerFO() | |||
.getCommonBorderPaddingBackground().getPaddingBefore(false, this); | |||
updateRelDims(contentRectOffsetX, contentRectOffsetY, autoHeight); | |||
int availableIPD = referenceIPD - getIPIndents(); | |||
if (getContentAreaIPD() > availableIPD) { | |||
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( | |||
getBlockContainerFO().getUserAgent().getEventBroadcaster()); | |||
eventProducer.objectTooWide(this, getBlockContainerFO().getName(), | |||
getContentAreaIPD(), context.getRefIPD(), | |||
getBlockContainerFO().getLocator()); | |||
} | |||
MinOptMax stackLimit = new MinOptMax(relDims.bpd); | |||
List returnedList; | |||
List contentList = new LinkedList(); | |||
List returnList = new LinkedList(); | |||
if (!breakBeforeServed) { | |||
breakBeforeServed = true; | |||
if (!context.suppressBreakBefore()) { | |||
if (addKnuthElementsForBreakBefore(returnList, context)) { | |||
return returnList; | |||
} | |||
} | |||
} | |||
if (!firstVisibleMarkServed) { | |||
addKnuthElementsForSpaceBefore(returnList, alignment); | |||
context.updateKeepWithPreviousPending(getKeepWithPrevious()); | |||
} | |||
addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); | |||
firstVisibleMarkServed = true; | |||
if (autoHeight && inlineElementList) { | |||
//Spaces, border and padding to be repeated at each break | |||
addPendingMarks(context); | |||
BlockLevelLayoutManager curLM; // currently active LM | |||
BlockLevelLayoutManager prevLM = null; // previously active LM | |||
LayoutContext childLC = new LayoutContext(0); | |||
if (lmStack.isEmpty()) { | |||
assert restartAtLM != null && restartAtLM.getParent() == this; | |||
curLM = (BlockLevelLayoutManager) restartAtLM; | |||
curLM.reset(); | |||
setCurrentChildLM(curLM); | |||
childLC.copyPendingMarksFrom(context); | |||
childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); | |||
childLC.setRefIPD(relDims.ipd); | |||
childLC.setWritingMode(getBlockContainerFO().getWritingMode()); | |||
if (curLM == this.childLMs.get(0)) { | |||
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); | |||
//Handled already by the parent (break collapsing, see above) | |||
} | |||
// get elements from curLM | |||
returnedList = curLM.getNextKnuthElements(childLC, alignment); | |||
} else { | |||
curLM = (BlockLevelLayoutManager) lmStack.pop(); | |||
setCurrentChildLM(curLM); | |||
childLC.copyPendingMarksFrom(context); | |||
childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); | |||
childLC.setRefIPD(relDims.ipd); | |||
childLC.setWritingMode(getBlockContainerFO().getWritingMode()); | |||
if (curLM == this.childLMs.get(0)) { | |||
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); | |||
//Handled already by the parent (break collapsing, see above) | |||
} | |||
// get elements from curLM | |||
returnedList = curLM.getNextKnuthElements(childLC, alignment, lmStack, | |||
restartPosition, restartAtLM); | |||
} | |||
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { | |||
//Propagate keep-with-previous up from the first child | |||
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); | |||
childLC.clearKeepWithPreviousPending(); | |||
} | |||
if (returnedList.size() == 1 | |||
&& ((ListElement)returnedList.get(0)).isForcedBreak()) { | |||
// a descendant of this block has break-before | |||
/* | |||
if (returnList.size() == 0) { | |||
// the first child (or its first child ...) has | |||
// break-before; | |||
// all this block, including space before, will be put in | |||
// the | |||
// following page | |||
bSpaceBeforeServed = false; | |||
}*/ | |||
contentList.addAll(returnedList); | |||
// "wrap" the Position inside each element | |||
// moving the elements from contentList to returnList | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
return returnList; | |||
} else { | |||
if (prevLM != null) { | |||
// there is a block handled by prevLM | |||
// before the one handled by curLM | |||
addInBetweenBreak(contentList, context, childLC); | |||
} | |||
contentList.addAll(returnedList); | |||
if (!returnedList.isEmpty()) { | |||
if (((ListElement) ListUtil.getLast(returnedList)) | |||
.isForcedBreak()) { | |||
// a descendant of this block has break-after | |||
if (curLM.isFinished()) { | |||
// there is no other content in this block; | |||
// it's useless to add space after before a page break | |||
setFinished(true); | |||
} | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
return returnList; | |||
} | |||
} | |||
} | |||
// propagate and clear | |||
context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); | |||
childLC.clearKeepsPending(); | |||
prevLM = curLM; | |||
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { | |||
curLM.reset(); | |||
childLC = new LayoutContext(0); | |||
childLC.copyPendingMarksFrom(context); | |||
// curLM is a ? | |||
childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit)); | |||
childLC.setRefIPD(relDims.ipd); | |||
childLC.setWritingMode(getBlockContainerFO().getWritingMode()); | |||
if (curLM == this.childLMs.get(0)) { | |||
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE); | |||
//Handled already by the parent (break collapsing, see above) | |||
} | |||
// 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 (returnedList.size() == 1 | |||
&& ((ListElement)returnedList.get(0)).isForcedBreak()) { | |||
// a descendant of this block has break-before | |||
/* | |||
if (returnList.size() == 0) { | |||
// the first child (or its first child ...) has | |||
// break-before; | |||
// all this block, including space before, will be put in | |||
// the | |||
// following page | |||
bSpaceBeforeServed = false; | |||
}*/ | |||
contentList.addAll(returnedList); | |||
// "wrap" the Position inside each element | |||
// moving the elements from contentList to returnList | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
return returnList; | |||
} else { | |||
if (prevLM != null) { | |||
// there is a block handled by prevLM | |||
// before the one handled by curLM | |||
addInBetweenBreak(contentList, context, childLC); | |||
} | |||
contentList.addAll(returnedList); | |||
if (returnedList.isEmpty()) { | |||
//Avoid NoSuchElementException below (happens with empty blocks) | |||
continue; | |||
} | |||
if (((ListElement) ListUtil.getLast(returnedList)) | |||
.isForcedBreak()) { | |||
// a descendant of this block has break-after | |||
if (curLM.isFinished()) { | |||
// there is no other content in this block; | |||
// it's useless to add space after before a page break | |||
setFinished(true); | |||
} | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
return returnList; | |||
} | |||
} | |||
// propagate and clear | |||
context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); | |||
childLC.clearKeepsPending(); | |||
prevLM = curLM; | |||
} | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
} else { | |||
MinOptMax range = new MinOptMax(relDims.ipd); | |||
BlockContainerBreaker breaker = new BlockContainerBreaker(this, range); | |||
breaker.doLayout(relDims.bpd, autoHeight); | |||
boolean contentOverflows = breaker.isOverflow(); | |||
if (autoHeight) { | |||
//Update content BPD now that it is known | |||
int newHeight = breaker.deferredAlg.totalWidth; | |||
boolean switchedProgressionDirection | |||
= (getBlockContainerFO().getReferenceOrientation() % 180 != 0); | |||
if (switchedProgressionDirection) { | |||
setContentAreaIPD(newHeight); | |||
} else { | |||
vpContentBPD = newHeight; | |||
} | |||
updateRelDims(contentRectOffsetX, contentRectOffsetY, false); | |||
} | |||
Position bcPosition = new BlockContainerPosition(this, breaker); | |||
returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false)); | |||
//TODO Handle min/opt/max for block-progression-dimension | |||
/* These two elements will be used to add stretchability to the above box | |||
returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, | |||
false, returnPosition, false)); | |||
returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0, | |||
LINE_NUMBER_ADJUSTMENT, returnPosition, false)); | |||
*/ | |||
if (contentOverflows) { | |||
BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get( | |||
getBlockContainerFO().getUserAgent().getEventBroadcaster()); | |||
boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW); | |||
eventProducer.viewportOverflow(this, getBlockContainerFO().getName(), | |||
breaker.getOverflowAmount(), needClip(), canRecover, | |||
getBlockContainerFO().getLocator()); | |||
} | |||
} | |||
addKnuthElementsForBorderPaddingAfter(returnList, true); | |||
addKnuthElementsForSpaceAfter(returnList, alignment); | |||
//All child content is processed. Only break-after can occur now, so... | |||
context.clearPendingMarks(); | |||
addKnuthElementsForBreakAfter(returnList, context); | |||
context.updateKeepWithNextPending(getKeepWithNext()); | |||
setFinished(true); | |||
return returnList; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRestartable() { | |||
return true; | |||
} | |||
private List getNextKnuthElementsAbsolute(LayoutContext context, int alignment) { | |||
autoHeight = false; | |||
@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Stack; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -67,9 +68,6 @@ 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. | |||
@@ -114,8 +112,19 @@ public class BlockLayoutManager extends BlockStackingLayoutManager | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment) { | |||
return getNextKnuthElements(context, alignment, null, null, null); | |||
} | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | |||
Position restartPosition, LayoutManager restartAtLM) { | |||
resetSpaces(); | |||
return super.getNextKnuthElements(context, alignment); | |||
if (lmStack == null) { | |||
return super.getNextKnuthElements(context, alignment); | |||
} else { | |||
return super.getNextKnuthElements(context, alignment, lmStack, restartPosition, | |||
restartAtLM); | |||
} | |||
} | |||
private void resetSpaces() { | |||
@@ -249,8 +258,8 @@ public class BlockLayoutManager extends BlockStackingLayoutManager | |||
// and put them in a new list; | |||
LinkedList positionList = new LinkedList(); | |||
Position pos; | |||
boolean bSpaceBefore = false; | |||
boolean bSpaceAfter = false; | |||
boolean spaceBefore = false; | |||
boolean spaceAfter = false; | |||
Position firstPos = null; | |||
Position lastPos = null; | |||
while (parentIter.hasNext()) { | |||
@@ -273,11 +282,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 | |||
bSpaceBefore = true; | |||
spaceBefore = true; | |||
//log.trace(" space before"); | |||
} else { | |||
// pos was in the element representing space-after | |||
bSpaceAfter = true; | |||
spaceAfter = true; | |||
//log.trace(" space-after"); | |||
} | |||
} else if (innerPosition.getLM() == this | |||
@@ -302,7 +311,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 | |||
@@ -341,7 +350,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager | |||
// + " spacing"); | |||
// add space before and / or after the paragraph | |||
// to reach a multiple of bpUnit | |||
if (bSpaceBefore && bSpaceAfter) { | |||
if (spaceBefore && spaceAfter) { | |||
foSpaceBefore = new SpaceVal(getBlockFO() | |||
.getCommonMarginBlock().spaceBefore, this).getSpace(); | |||
foSpaceAfter = new SpaceVal(getBlockFO() | |||
@@ -354,7 +363,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager | |||
+ foSpaceBefore.min | |||
+ foSpaceAfter.min) | |||
* bpUnit - splitLength - adjustedSpaceBefore; | |||
} else if (bSpaceBefore) { | |||
} else if (spaceBefore) { | |||
adjustedSpaceBefore = neededUnits(splitLength | |||
+ foSpaceBefore.min) | |||
* bpUnit - splitLength; | |||
@@ -547,5 +556,10 @@ public class BlockLayoutManager extends BlockStackingLayoutManager | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRestartable() { | |||
return true; | |||
} | |||
} | |||
@@ -23,6 +23,7 @@ import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Stack; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -30,12 +31,12 @@ import org.apache.commons.logging.LogFactory; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.Block; | |||
import org.apache.fop.area.BlockParent; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.Constants; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.properties.BreakPropertySet; | |||
import org.apache.fop.fo.properties.CommonBorderPaddingBackground; | |||
import org.apache.fop.fo.properties.SpaceProperty; | |||
import org.apache.fop.fo.properties.KeepProperty; | |||
import org.apache.fop.fo.properties.SpaceProperty; | |||
import org.apache.fop.layoutmgr.inline.InlineLayoutManager; | |||
import org.apache.fop.layoutmgr.inline.LineLayoutManager; | |||
import org.apache.fop.traits.MinOptMax; | |||
@@ -54,31 +55,26 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
*/ | |||
private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class); | |||
/** | |||
* 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; | |||
protected BlockParent parentArea; | |||
/** Value of the block-progression-unit (non-standard property) */ | |||
protected int bpUnit = 0; | |||
protected int bpUnit; | |||
/** space-before value adjusted for block-progression-unit handling */ | |||
protected int adjustedSpaceBefore = 0; | |||
protected int adjustedSpaceBefore; | |||
/** space-after value adjusted for block-progression-unit handling */ | |||
protected int adjustedSpaceAfter = 0; | |||
protected int adjustedSpaceAfter; | |||
/** Only used to store the original list when createUnitElements is called */ | |||
protected List storedList = null; | |||
protected List storedList; | |||
/** Indicates whether break before has been served or not */ | |||
protected boolean breakBeforeServed = false; | |||
protected boolean breakBeforeServed; | |||
/** Indicates whether the first visible mark has been returned by this LM, yet */ | |||
protected boolean firstVisibleMarkServed = false; | |||
protected boolean firstVisibleMarkServed; | |||
/** Reference IPD available */ | |||
protected int referenceIPD = 0; | |||
protected int referenceIPD; | |||
/** the effective start-indent value */ | |||
protected int startIndent = 0; | |||
protected int startIndent; | |||
/** the effective end-indent value */ | |||
protected int endIndent = 0; | |||
protected int endIndent; | |||
/** | |||
* Holds the (one-time use) fo:block space-before | |||
* and -after properties. Large fo:blocks are split | |||
@@ -88,13 +84,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 = null; | |||
protected MinOptMax foSpaceBefore; | |||
/** see foSpaceBefore */ | |||
protected MinOptMax foSpaceAfter = null; | |||
protected MinOptMax foSpaceAfter; | |||
private Position auxiliaryPosition; | |||
private int contentAreaIPD = 0; | |||
private int contentAreaIPD; | |||
/** | |||
* @param node the fo this LM deals with | |||
@@ -248,38 +244,27 @@ 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 returnList = new LinkedList(); | |||
List elements = new LinkedList(); | |||
if (!breakBeforeServed) { | |||
breakBeforeServed = true; | |||
if (!context.suppressBreakBefore()) { | |||
if (addKnuthElementsForBreakBefore(returnList, context)) { | |||
return returnList; | |||
if (addKnuthElementsForBreakBefore(elements, context)) { | |||
return elements; | |||
} | |||
} | |||
} | |||
if (!firstVisibleMarkServed) { | |||
addKnuthElementsForSpaceBefore(returnList, alignment); | |||
addKnuthElementsForSpaceBefore(elements, alignment); | |||
context.updateKeepWithPreviousPending(getKeepWithPrevious()); | |||
} | |||
addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed); | |||
addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed); | |||
firstVisibleMarkServed = true; | |||
//Spaces, border and padding to be repeated at each break | |||
@@ -288,142 +273,311 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
//Used to indicate a special break-after case when all content has already been generated. | |||
BreakElement forcedBreakAfterLast = null; | |||
while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) { | |||
LayoutManager currentChildLM; | |||
while ((currentChildLM = (LayoutManager) 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) | |||
} | |||
// get elements from curLM | |||
returnedList = curLM.getNextKnuthElements(childLC, alignment); | |||
if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) { | |||
List childrenElements = getNextChildElements(currentChildLM, context, childLC, | |||
alignment); | |||
if (contentList.isEmpty()) { | |||
//Propagate keep-with-previous up from the first child | |||
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); | |||
childLC.clearKeepWithPreviousPending(); | |||
} | |||
if (returnedList != null | |||
&& returnedList.size() == 1 | |||
&& ((ListElement) returnedList.get(0)).isForcedBreak()) { | |||
if (childrenElements != null && !childrenElements.isEmpty()) { | |||
if (!contentList.isEmpty() | |||
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) { | |||
// 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); | |||
context.clearPendingMarks(); | |||
break; | |||
} | |||
if (curLM.isFinished() && !hasNextChildLM()) { | |||
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)); | |||
} | |||
// a descendant of this block has break-before | |||
forcedBreakAfterLast = (BreakElement) returnedList.get(0); | |||
contentList.addAll(childrenElements); | |||
wrapPositionElements(contentList, elements); | |||
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; | |||
} | |||
} | |||
context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); | |||
} | |||
} | |||
if (!contentList.isEmpty()) { | |||
wrapPositionElements(contentList, elements); | |||
} 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)); | |||
} | |||
addKnuthElementsForBorderPaddingAfter(elements, true); | |||
addKnuthElementsForSpaceAfter(elements, alignment); | |||
//All child content is processed. Only break-after can occur now, so... | |||
context.clearPendingMarks(); | |||
if (forcedBreakAfterLast == null) { | |||
addKnuthElementsForBreakAfter(elements, context); | |||
} else { | |||
forcedBreakAfterLast.clearPendingMarks(); | |||
elements.add(forcedBreakAfterLast); | |||
} | |||
context.updateKeepWithNextPending(getKeepWithNext()); | |||
setFinished(true); | |||
return elements; | |||
} | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | |||
Position restartPosition, LayoutManager restartAtLM) { | |||
referenceIPD = context.getRefIPD(); | |||
updateContentAreaIPDwithOverconstrainedAdjust(); | |||
List contentList = new LinkedList(); | |||
List elements = new LinkedList(); | |||
if (!breakBeforeServed) { | |||
breakBeforeServed = true; | |||
if (!context.suppressBreakBefore()) { | |||
if (addKnuthElementsForBreakBefore(elements, context)) { | |||
return elements; | |||
} | |||
} | |||
} | |||
if (!firstVisibleMarkServed) { | |||
addKnuthElementsForSpaceBefore(elements, alignment); | |||
context.updateKeepWithPreviousPending(getKeepWithPrevious()); | |||
} | |||
addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed); | |||
firstVisibleMarkServed = true; | |||
//Spaces, border and padding to be repeated at each break | |||
addPendingMarks(context); | |||
//Used to indicate a special break-after case when all content has already been generated. | |||
BreakElement forcedBreakAfterLast = null; | |||
LayoutContext childLC = new LayoutContext(0); | |||
List childrenElements; | |||
LayoutManager currentChildLM; | |||
if (lmStack.isEmpty()) { | |||
assert restartAtLM != null && restartAtLM.getParent() == this; | |||
currentChildLM = restartAtLM; | |||
currentChildLM.reset(); | |||
setCurrentChildLM(currentChildLM); | |||
childrenElements = getNextChildElements(currentChildLM, context, childLC, | |||
alignment); | |||
} else { | |||
currentChildLM = (BlockLevelLayoutManager) lmStack.pop(); | |||
setCurrentChildLM(currentChildLM); | |||
childrenElements = getNextChildElements(currentChildLM, context, childLC, alignment, | |||
lmStack, restartPosition, restartAtLM); | |||
} | |||
if (contentList.isEmpty()) { | |||
//Propagate keep-with-previous up from the first child | |||
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); | |||
} | |||
if (childrenElements != null && !childrenElements.isEmpty()) { | |||
if (!contentList.isEmpty() | |||
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) { | |||
// 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); | |||
context.clearPendingMarks(); | |||
break; | |||
// break; TODO | |||
} | |||
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)); | |||
elements.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 */ | |||
contentList.addAll(childrenElements); | |||
// "wrap" the Position inside each element | |||
// moving the elements from contentList to returnList | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
wrapPositionElements(contentList, elements); | |||
return returnList; | |||
return elements; | |||
} else { | |||
if (returnedList == null || returnedList.isEmpty()) { | |||
//Avoid NoSuchElementException below (happens with empty blocks) | |||
continue; | |||
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; TODO | |||
} | |||
wrapPositionElements(contentList, elements); | |||
return elements; | |||
} | |||
if (prevLM != null | |||
&& !ElementListUtils.startsWithForcedBreak(returnedList)) { | |||
} | |||
context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); | |||
} | |||
while ((currentChildLM = (LayoutManager) getChildLM()) != null) { | |||
currentChildLM.reset(); // TODO won't work with forced breaks | |||
childLC = new LayoutContext(0); | |||
childrenElements = getNextChildElements(currentChildLM, context, childLC, | |||
alignment); | |||
if (contentList.isEmpty()) { | |||
//Propagate keep-with-previous up from the first child | |||
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); | |||
} | |||
if (childrenElements != null && !childrenElements.isEmpty()) { | |||
if (!contentList.isEmpty() | |||
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) { | |||
// 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); | |||
} | |||
contentList.addAll(returnedList); | |||
if (ElementListUtils.endsWithForcedBreak(returnedList)) { | |||
// a descendant of this block has break-after | |||
if (curLM.isFinished() && !hasNextChildLM()) { | |||
forcedBreakAfterLast = (BreakElement) ListUtil | |||
.removeLast(contentList); | |||
if (childrenElements.size() == 1 | |||
&& ElementListUtils.startsWithForcedBreak(childrenElements)) { | |||
if (currentChildLM.isFinished() && !hasNextChildLM()) { | |||
// a descendant of this block has break-before | |||
forcedBreakAfterLast = (BreakElement) childrenElements.get(0); | |||
context.clearPendingMarks(); | |||
break; | |||
} | |||
/* extension: conversione di tutta la sequenza fin'ora ottenuta */ | |||
if (bpUnit > 0) { | |||
storedList = contentList; | |||
contentList = createUnitElements(contentList); | |||
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)); | |||
} | |||
/* end of extension */ | |||
// a descendant of this block has break-before | |||
contentList.addAll(childrenElements); | |||
returnedList = new LinkedList(); | |||
wrapPositionElements(contentList, returnList); | |||
wrapPositionElements(contentList, elements); | |||
return 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; | |||
} | |||
} | |||
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, returnList); | |||
wrapPositionElements(contentList, elements); | |||
} else if (forcedBreakAfterLast == null) { | |||
// Empty fo:block, zero-length box makes sure the IDs and/or markers | |||
// are registered. | |||
returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true)); | |||
elements.add(new KnuthBox(0, notifyPos(new Position(this)), true)); | |||
} | |||
addKnuthElementsForBorderPaddingAfter(returnList, true); | |||
addKnuthElementsForSpaceAfter(returnList, alignment); | |||
addKnuthElementsForBorderPaddingAfter(elements, true); | |||
addKnuthElementsForSpaceAfter(elements, alignment); | |||
//All child content is processed. Only break-after can occur now, so... | |||
context.clearPendingMarks(); | |||
if (forcedBreakAfterLast == null) { | |||
addKnuthElementsForBreakAfter(returnList, context); | |||
} | |||
if (forcedBreakAfterLast != null) { | |||
addKnuthElementsForBreakAfter(elements, context); | |||
} else { | |||
forcedBreakAfterLast.clearPendingMarks(); | |||
returnList.add(forcedBreakAfterLast); | |||
elements.add(forcedBreakAfterLast); | |||
} | |||
context.updateKeepWithNextPending(getKeepWithNext()); | |||
setFinished(true); | |||
return returnList; | |||
return elements; | |||
} | |||
private List getNextChildElements(LayoutManager childLM, LayoutContext context, | |||
LayoutContext childLC, int alignment) { | |||
return getNextChildElements(childLM, context, childLC, alignment, null, null, null); | |||
} | |||
private List getNextChildElements(LayoutManager childLM, LayoutContext context, | |||
LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition, | |||
LayoutManager restartAtLM) { | |||
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) | |||
} | |||
if (lmStack == null) { | |||
return childLM.getNextKnuthElements(childLC, alignment); | |||
} else { | |||
if (childLM instanceof LineLayoutManager) { | |||
return ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment, | |||
(LeafPosition) restartPosition); | |||
} else { | |||
return childLM.getNextKnuthElements(childLC, alignment, | |||
lmStack, restartPosition, restartAtLM); | |||
} | |||
} | |||
} | |||
/** | |||
@@ -1654,5 +1808,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager | |||
return -1; | |||
} | |||
/** {@inheritDoc} */ | |||
public void reset() { | |||
super.reset(); | |||
breakBeforeServed = false; | |||
firstVisibleMarkServed = false; | |||
// TODO startIndent, endIndent | |||
} | |||
} | |||
@@ -491,6 +491,9 @@ public abstract class BreakingAlgorithm { | |||
elementIndex, previousIsBox, allowedBreaks).isBox(); | |||
if (activeNodeCount == 0) { | |||
if (ipdChanged()) { | |||
return handleIpdChange(); | |||
} | |||
if (!force) { | |||
log.debug("Could not find a set of breaking points " + threshold); | |||
return 0; | |||
@@ -535,6 +538,14 @@ public abstract class BreakingAlgorithm { | |||
return line; | |||
} | |||
protected boolean ipdChanged() { | |||
return false; | |||
} | |||
protected int handleIpdChange() { | |||
throw new IllegalStateException(); | |||
} | |||
/** | |||
* Recover from a {@link KnuthNode} leading to a line that is too long. | |||
* The default implementation creates a new node corresponding to a break | |||
@@ -1283,12 +1294,8 @@ public abstract class BreakingAlgorithm { | |||
* @return the width/length in millipoints | |||
*/ | |||
protected int getLineWidth(int line) { | |||
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; | |||
} | |||
assert lineWidth >= 0; | |||
return this.lineWidth; | |||
} | |||
/** @return the constant line/part width or -1 if there is no such value */ | |||
@@ -1321,7 +1328,7 @@ public abstract class BreakingAlgorithm { | |||
* @param par the corresponding paragraph | |||
* @param total the number of lines into which the paragraph will be broken | |||
*/ | |||
private void calculateBreakPoints(KnuthNode node, KnuthSequence par, | |||
protected void calculateBreakPoints(KnuthNode node, KnuthSequence par, | |||
int total) { | |||
KnuthNode bestActiveNode = node; | |||
// use bestActiveNode to determine the optimum breakpoints |
@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
import java.util.Stack; | |||
import org.apache.commons.logging.Log; | |||
import org.apache.commons.logging.LogFactory; | |||
@@ -29,8 +30,6 @@ 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. | |||
@@ -64,108 +63,151 @@ public class FlowLayoutManager extends BlockStackingLayoutManager | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment) { | |||
// set layout dimensions | |||
int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth(); | |||
int flowBPD = getCurrentPV().getBodyRegion().getBPD(); | |||
List elements = new LinkedList(); | |||
// 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; | |||
LayoutManager currentChildLM; | |||
while ((currentChildLM = getChildLM()) != null) { | |||
if (addChildElements(elements, currentChildLM, context, alignment) != null) { | |||
return elements; | |||
} | |||
} | |||
SpaceResolver.resolveElementList(elements); | |||
setFinished(true); | |||
assert !elements.isEmpty(); | |||
return elements; | |||
} | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment, | |||
Position positionAtIPDChange, LayoutManager restartAtLM) { | |||
List elements = new LinkedList(); | |||
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(); | |||
LayoutManager currentChildLM = positionAtIPDChange.getLM(); | |||
if (currentChildLM == null) { | |||
throw new IllegalStateException( | |||
"Cannot find layout manager from where to re-start layout after IPD change"); | |||
} | |||
if (restartAtLM != null && restartAtLM.getParent() == this) { | |||
currentChildLM = restartAtLM; | |||
setCurrentChildLM(currentChildLM); | |||
currentChildLM.reset(); | |||
if (addChildElements(elements, currentChildLM, context, alignment) != null) { | |||
return elements; | |||
} | |||
} else { | |||
Stack lmStack = new Stack(); | |||
while (currentChildLM.getParent() != this) { | |||
lmStack.push(currentChildLM); | |||
currentChildLM = currentChildLM.getParent(); | |||
} | |||
setCurrentChildLM(currentChildLM); | |||
if (addChildElements(elements, currentChildLM, context, alignment, lmStack, | |||
positionAtIPDChange, restartAtLM) != null) { | |||
return elements; | |||
} | |||
} | |||
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; | |||
while ((currentChildLM = getChildLM()) != null) { | |||
currentChildLM.reset(); // TODO won't work with forced breaks | |||
if (addChildElements(elements, currentChildLM, context, alignment) != null) { | |||
return elements; | |||
} | |||
} | |||
// Set up a LayoutContext | |||
//MinOptMax bpd = context.getStackLimit(); | |||
SpaceResolver.resolveElementList(elements); | |||
setFinished(true); | |||
LayoutContext childLC = new LayoutContext(0); | |||
childLC.setStackLimitBP(context.getStackLimitBP()); | |||
childLC.setRefIPD(context.getRefIPD()); | |||
childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode()); | |||
assert !elements.isEmpty(); | |||
return elements; | |||
} | |||
// 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(); | |||
} | |||
private List addChildElements(List elements, LayoutManager childLM, LayoutContext context, | |||
int alignment) { | |||
return addChildElements(elements, childLM, context, alignment, null, null, null); | |||
} | |||
// "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; | |||
} | |||
private List addChildElements(List elements, LayoutManager childLM, LayoutContext context, | |||
int alignment, Stack lmStack, Position position, LayoutManager restartAtLM) { | |||
if (handleSpanChange(childLM, elements, context)) { | |||
SpaceResolver.resolveElementList(elements); | |||
return elements; | |||
} | |||
LayoutContext childLC = new LayoutContext(0); | |||
List childrenElements = getNextChildElements(childLM, context, childLC, alignment, lmStack, | |||
position, restartAtLM); | |||
if (elements.isEmpty()) { | |||
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending()); | |||
} | |||
if (!elements.isEmpty() | |||
&& !ElementListUtils.startsWithForcedBreak(childrenElements)) { | |||
addInBetweenBreak(elements, context, childLC); | |||
} | |||
context.updateKeepWithNextPending(childLC.getKeepWithNextPending()); | |||
elements.addAll(childrenElements); | |||
if (ElementListUtils.endsWithForcedBreak(elements)) { | |||
// a descendant of this flow has break-before or break-after | |||
if (childLM.isFinished() && !hasNextChildLM()) { | |||
setFinished(true); | |||
} | |||
SpaceResolver.resolveElementList(elements); | |||
return elements; | |||
} | |||
return null; | |||
} | |||
//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; | |||
} else { | |||
return false; | |||
} | |||
} | |||
SpaceResolver.resolveElementList(returnList); | |||
setFinished(true); | |||
private List getNextChildElements(LayoutManager childLM, LayoutContext context, | |||
LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition, | |||
LayoutManager restartLM) { | |||
childLC.setStackLimitBP(context.getStackLimitBP()); | |||
childLC.setRefIPD(context.getRefIPD()); | |||
childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode()); | |||
if (returnList.size() > 0) { | |||
return returnList; | |||
List childrenElements; | |||
if (lmStack == null) { | |||
childrenElements = childLM.getNextKnuthElements(childLC, alignment); | |||
} else { | |||
return null; | |||
childrenElements = childLM.getNextKnuthElements(childLC, | |||
alignment, lmStack, restartPosition, restartLM); | |||
} | |||
assert !childrenElements.isEmpty(); | |||
// "wrap" the Position inside each element | |||
List tempList = childrenElements; | |||
childrenElements = new LinkedList(); | |||
wrapPositionElements(tempList, childrenElements); | |||
return childrenElements; | |||
} | |||
/** | |||
@@ -353,5 +395,10 @@ public class FlowLayoutManager extends BlockStackingLayoutManager | |||
return getCurrentPV().getBodyRegion().getBPD(); | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRestartable() { | |||
return true; | |||
} | |||
} | |||
@@ -57,16 +57,12 @@ public class InlineKnuthSequence extends KnuthSequence { | |||
return true; | |||
} | |||
/* (non-Javadoc) | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public boolean canAppendSequence(KnuthSequence sequence) { | |||
return sequence.isInlineSequence() && !isClosed; | |||
} | |||
/* (non-Javadoc) | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public boolean appendSequence(KnuthSequence sequence) { | |||
if (!canAppendSequence(sequence)) { | |||
return false; | |||
@@ -83,18 +79,14 @@ public class InlineKnuthSequence extends KnuthSequence { | |||
return true; | |||
} | |||
/* (non-Javadoc) | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether, | |||
BreakElement breakElement) { | |||
return appendSequence(sequence); | |||
} | |||
/* (non-Javadoc) | |||
* {@inheritDoc} | |||
*/ | |||
/** {@inheritDoc} */ | |||
public KnuthSequence endSequence() { | |||
if (!isClosed) { | |||
add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false)); |
@@ -78,15 +78,6 @@ 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; | |||
@@ -158,7 +149,7 @@ public class LayoutContext { | |||
this.flags = parentLC.flags; | |||
this.refIPD = parentLC.refIPD; | |||
this.writingMode = parentLC.writingMode; | |||
setStackLimitsFrom(parentLC); | |||
setStackLimitBP(parentLC.getStackLimitBP()); | |||
this.leadingSpace = parentLC.leadingSpace; //??? | |||
this.trailingSpace = parentLC.trailingSpace; //??? | |||
this.hyphContext = parentLC.hyphContext; | |||
@@ -183,7 +174,6 @@ public class LayoutContext { | |||
this.flags = flags; | |||
this.refIPD = 0; | |||
stackLimitBP = new MinOptMax(0); | |||
stackLimitIP = new MinOptMax(0); | |||
leadingSpace = null; | |||
trailingSpace = null; | |||
} | |||
@@ -397,31 +387,6 @@ 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. | |||
*/ | |||
@@ -662,8 +627,6 @@ 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" |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.List; | |||
import java.util.Stack; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.datatypes.PercentBaseContext; | |||
@@ -219,4 +220,36 @@ public interface LayoutManager extends PercentBaseContext { | |||
* @return the same Position but with a position index | |||
*/ | |||
Position notifyPos(Position pos); | |||
/** | |||
* Re-initializes this layout manager in order to re-generate its Knuth | |||
* elements according to a new IPD value. | |||
*/ | |||
void reset(); | |||
/** | |||
* Returns {@code true} if this layout manager is able to re-generate its | |||
* Knuth elements after an IPD change. | |||
* | |||
* @return {@code true} if this layout manager can be restarted after an IPD | |||
* change | |||
*/ | |||
boolean isRestartable(); | |||
/** | |||
* Returns an updated list of Knuth elements corresponding to this layout | |||
* manager, after a change of IPD has been detected. | |||
* | |||
* @param context the layout context | |||
* @param alignment the alignment | |||
* @param lmStack the stack of LMs that are active at the IPD change | |||
* @param positionAtIPDChange the position corresponding to the element | |||
* finishing the page before the IPD change | |||
* @param restartAtLM if not null, the layout manager from which to restart. | |||
* That is, the IPD change occurs between two block elements and not inside | |||
* a paragraph | |||
* @return an updated list of elements, taking the new IPD into account | |||
*/ | |||
List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack, | |||
Position positionAtIPDChange, LayoutManager restartAtLM); | |||
} |
@@ -21,15 +21,20 @@ package org.apache.fop.layoutmgr; | |||
public class LeafPosition extends Position { | |||
private int iLeafPos; | |||
private int leafPos; | |||
public LeafPosition(LayoutManager lm, int pos) { | |||
super(lm); | |||
iLeafPos = pos; | |||
leafPos = pos; | |||
} | |||
public LeafPosition(LayoutManager layoutManager, int pos, int index) { | |||
super(layoutManager, index); | |||
leafPos = pos; | |||
} | |||
public int getLeafPos() { | |||
return iLeafPos; | |||
return leafPos; | |||
} | |||
public boolean generatesAreas() { |
@@ -77,6 +77,14 @@ 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() { | |||
@@ -121,6 +129,12 @@ public class PageBreaker extends AbstractBreaker { | |||
/** {@inheritDoc} */ | |||
protected int getNextBlockList(LayoutContext childLC, | |||
int nextSequenceStartsOn) { | |||
return getNextBlockList(childLC, nextSequenceStartsOn, null, null, null); | |||
} | |||
/** {@inheritDoc} */ | |||
protected int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn, | |||
Position positionAtIPDChange, LayoutManager restartLM, List firstElements) { | |||
if (!firstPart) { | |||
// if this is the first page that will be created by | |||
// the current BlockSequence, it could have a break | |||
@@ -132,7 +146,8 @@ public class PageBreaker extends AbstractBreaker { | |||
pageBreakHandled = true; | |||
pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(), | |||
pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); | |||
return super.getNextBlockList(childLC, nextSequenceStartsOn); | |||
return super.getNextBlockList(childLC, nextSequenceStartsOn, positionAtIPDChange, | |||
restartLM, firstElements); | |||
} | |||
private boolean containsFootnotes(List contentList, LayoutContext context) { | |||
@@ -209,6 +224,24 @@ public class PageBreaker extends AbstractBreaker { | |||
return contentList; | |||
} | |||
/** {@inheritDoc} */ | |||
protected List getNextKnuthElements(LayoutContext context, int alignment, | |||
Position positionAtIPDChange, LayoutManager restartAtLM) { | |||
List contentList = null; | |||
do { | |||
contentList = childFLM.getNextKnuthElements(context, alignment, positionAtIPDChange, | |||
restartAtLM); | |||
} while (!childFLM.isFinished() && contentList == null); | |||
// scan contentList, searching for footnotes | |||
if (containsFootnotes(contentList, context)) { | |||
// handle the footnote separator | |||
handleFootnoteSeparator(); | |||
} | |||
return contentList; | |||
} | |||
/** | |||
* @return current display alignment | |||
*/ |
@@ -96,6 +96,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
//Controls whether a single part should be forced if possible (ex. block-container) | |||
private boolean favorSinglePart = false; | |||
private boolean ipdChange; | |||
private KnuthNode bestNodeForIPDChange; | |||
//Used to keep track of switches in keep-context | |||
private int currentKeepContext = Constants.EN_AUTO; | |||
private KnuthNode lastBeforeKeepContextSwitch; | |||
@@ -1073,4 +1076,63 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
} | |||
/** {@inheritDoc} */ | |||
protected boolean ipdChanged() { | |||
return ipdChange; | |||
} | |||
/** {@inheritDoc} */ | |||
protected int handleIpdChange() { | |||
log.trace("Best node for ipd change:" + bestNodeForIPDChange); | |||
// TODO finish() | |||
/* | |||
* The third parameter is used to determine if this is the last page, so | |||
* if the content must be vertically justified or not. If we are here | |||
* this means that there is further content and the next page has a | |||
* different ipd. So tweak the parameter to fall into the non-last-page | |||
* case. | |||
*/ | |||
calculateBreakPoints(bestNodeForIPDChange, par, bestNodeForIPDChange.line + 1); | |||
activeLines = null; | |||
return bestNodeForIPDChange.line; | |||
} | |||
/** | |||
* Add a node at the end of the given line's existing active nodes. | |||
* If this is the first node in the line, adjust endLine accordingly. | |||
* @param line number of the line ending at the node's corresponding breakpoint | |||
* @param node the active node to add | |||
*/ | |||
protected void addNode(int line, KnuthNode node) { | |||
if (node.position < par.size() - 1 && line > 0 && ipdChange(line - 1)) { | |||
log.trace("IPD changes at page " + line); | |||
ipdChange = true; | |||
if (bestNodeForIPDChange == null | |||
|| node.totalDemerits < bestNodeForIPDChange.totalDemerits) { | |||
bestNodeForIPDChange = node; | |||
} | |||
} else { | |||
if (node.position == par.size() - 1) { | |||
/* | |||
* The whole sequence could actually fit on the last page before | |||
* the IPD change. No need to do any special handling. | |||
*/ | |||
ipdChange = false; | |||
} | |||
super.addNode(line, node); | |||
} | |||
} | |||
KnuthNode getBestNodeBeforeIPDChange() { | |||
return bestNodeForIPDChange; | |||
} | |||
/** {@inheritDoc} */ | |||
protected boolean ipdChange(int line) { | |||
if (pageProvider == null) { | |||
return false; | |||
} | |||
return pageProvider.ipdChange(line); | |||
} | |||
} |
@@ -160,6 +160,33 @@ public class PageProvider implements Constants { | |||
return new int[] {colIndex, columnCount}; | |||
} | |||
/** | |||
* Returns true if the part following the given one has a different IPD. | |||
* | |||
* @param index index of the current part | |||
* @return true if the following part has a different IPD, false otherwise | |||
*/ | |||
public boolean ipdChange(int index) { | |||
int columnCount = 0; | |||
int colIndex = startColumnOfCurrentElementList + index; | |||
int pageIndex = -1; | |||
Page page; | |||
do { | |||
colIndex -= columnCount; | |||
pageIndex++; | |||
page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST); | |||
columnCount = page.getPageViewport().getCurrentSpan().getColumnCount(); | |||
} while (colIndex >= columnCount); | |||
if (colIndex + 1 < columnCount) { | |||
// Next part is a column on same page => same IPD | |||
return false; | |||
} else { | |||
Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST); | |||
return page.getPageViewport().getBodyRegion().getIPD() | |||
!= nextPage.getPageViewport().getBodyRegion().getIPD(); | |||
} | |||
} | |||
/** | |||
* Checks if a break at the passed index would start a new page | |||
* @param index the index of the element before the break |
@@ -28,6 +28,11 @@ public class Position { | |||
layoutManager = lm; | |||
} | |||
public Position(LayoutManager lm, int index) { | |||
this(lm); | |||
setIndex(index); | |||
} | |||
public LayoutManager getLM() { | |||
return layoutManager; | |||
} |
@@ -19,7 +19,6 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
@@ -565,6 +564,11 @@ public class SpaceResolver { | |||
public Position getOriginalBreakPosition() { | |||
return this.originalPosition; | |||
} | |||
public Position getPosition() { | |||
return originalPosition; | |||
} | |||
} | |||
/** |
@@ -21,10 +21,6 @@ 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; | |||
@@ -35,10 +31,7 @@ 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. | |||
@@ -48,11 +41,6 @@ import org.apache.fop.util.ListUtil; | |||
*/ | |||
public class StaticContentLayoutManager extends BlockStackingLayoutManager { | |||
/** | |||
* logging instance | |||
*/ | |||
private static Log log = LogFactory.getLog(StaticContentLayoutManager.class); | |||
private RegionReference targetRegion; | |||
private Block targetBlock; | |||
private SideRegion regionFO; | |||
@@ -89,96 +77,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { | |||
/** {@inheritDoc} */ | |||
public List getNextKnuthElements(LayoutContext context, int alignment) { | |||
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; | |||
} | |||
throw new IllegalStateException(); | |||
} | |||
/** |
@@ -27,6 +27,7 @@ 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; | |||
@@ -43,7 +44,6 @@ 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,8 +111,6 @@ 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; | |||
@@ -129,8 +127,7 @@ 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(); | |||
@@ -149,8 +146,7 @@ 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); | |||
} | |||
@@ -248,8 +248,6 @@ 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), | |||
@@ -274,14 +272,6 @@ 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:"); |
@@ -19,12 +19,13 @@ | |||
package org.apache.fop.layoutmgr.inline; | |||
import java.util.LinkedList; | |||
import java.util.Iterator; | |||
import java.util.LinkedList; | |||
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; | |||
@@ -34,8 +35,6 @@ 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; | |||
/** | |||
@@ -62,12 +61,6 @@ 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). | |||
*/ | |||
@@ -78,9 +71,6 @@ 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 | |||
@@ -148,22 +138,6 @@ 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 |
@@ -20,6 +20,7 @@ | |||
package org.apache.fop.layoutmgr.inline; | |||
import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.ListIterator; | |||
@@ -116,8 +117,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
* inline break positions. | |||
*/ | |||
private static class LineBreakPosition extends LeafPosition { | |||
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 parIndex; // index of the Paragraph this Position refers to | |||
private int startIndex; //index of the first element this Position refers to | |||
private int availableShrink; | |||
private int availableStretch; | |||
private int difference; | |||
@@ -130,16 +131,16 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
private int spaceAfter; | |||
private int baseline; | |||
LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex, | |||
LineBreakPosition(LayoutManager lm, int index, int startIndex, int breakIndex, | |||
int shrink, int stretch, int diff, | |||
double ipdA, double adjust, int ind, | |||
int lh, int lw, int sb, int sa, int bl) { | |||
super(lm, iBreakIndex); | |||
super(lm, breakIndex); | |||
availableShrink = shrink; | |||
availableStretch = stretch; | |||
difference = diff; | |||
iParIndex = index; | |||
this.iStartIndex = iStartIndex; | |||
parIndex = index; | |||
this.startIndex = startIndex; | |||
ipdAdjust = ipdA; | |||
dAdjust = adjust; | |||
startIndent = ind; | |||
@@ -167,18 +168,18 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
private Length lineHeight; | |||
private int lead; | |||
private int follow; | |||
private AlignmentContext alignmentContext = null; | |||
private AlignmentContext alignmentContext; | |||
private List knuthParagraphs = null; | |||
private int iReturnedLBP = 0; | |||
// parameters of Knuth's algorithm: | |||
// penalty value for flagged penalties | |||
private int flaggedPenalty = 50; | |||
private List knuthParagraphs; | |||
private LineLayoutPossibilities lineLayouts; | |||
private List lineLayoutsList; | |||
private int iLineWidth = 0; | |||
private int ipd = 0; | |||
/** | |||
* When layout must be re-started due to a change of IPD, there is no need | |||
* to perform hyphenation on the remaining Knuth sequence once again. | |||
*/ | |||
private boolean hyphenationPerformed; | |||
/** | |||
* this constant is used to create elements when text-align is center: | |||
@@ -238,7 +239,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
} else { | |||
lineFiller = new MinOptMax(lastLineEndIndent, | |||
lastLineEndIndent, | |||
layoutManager.iLineWidth); | |||
layoutManager.ipd); | |||
} | |||
// add auxiliary elements at the beginning of the paragraph | |||
@@ -319,11 +320,9 @@ 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, | |||
@@ -334,22 +333,17 @@ 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 (super.log.isTraceEnabled()) { | |||
super.log.trace( | |||
"Layout possibility in " + lineCount + " lines; break at position:"); | |||
if (log.isTraceEnabled()) { | |||
log.trace("Layout possibility in " + lineCount + " lines; break at position:"); | |||
} | |||
} | |||
@@ -430,7 +424,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 == iLineWidth); | |||
boolean bZeroHeightLine = (difference == ipd); | |||
// if line-stacking-strategy is "font-height", the line height | |||
// is not affected by its content | |||
@@ -486,7 +480,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
firstElementIndex, lastElementIndex, | |||
availableShrink, availableStretch, | |||
difference, ratio, 0, indent, | |||
0, iLineWidth, 0, 0, 0); | |||
0, ipd, 0, 0, 0); | |||
} else { | |||
return new LineBreakPosition(thisLLM, | |||
knuthParagraphs.indexOf(par), | |||
@@ -494,18 +488,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
availableShrink, availableStretch, | |||
difference, ratio, 0, indent, | |||
lineLead + lineFollow, | |||
iLineWidth, spaceBefore, spaceAfter, | |||
ipd, spaceBefore, spaceAfter, | |||
lineLead); | |||
} | |||
} | |||
public int findBreakingPoints(Paragraph par, /*int lineWidth,*/ | |||
double threshold, boolean force, | |||
int allowedBreaks) { | |||
return super.findBreakingPoints(par, /*lineWidth,*/ | |||
threshold, force, allowedBreaks); | |||
} | |||
protected int filterActiveNodes() { | |||
KnuthNode bestActiveNode = null; | |||
@@ -578,13 +565,10 @@ 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(); | |||
ipd = context.getRefIPD(); | |||
//PHASE 1: Create Knuth elements | |||
if (knuthParagraphs == null) { | |||
@@ -606,34 +590,33 @@ 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 | |||
public List getNextKnuthElements(LayoutContext context, int alignment, | |||
LeafPosition restartPosition) { | |||
log.trace("Restarting line breaking from index " + restartPosition.getIndex()); | |||
int parIndex = restartPosition.getLeafPos(); | |||
Paragraph paragraph = (Paragraph) knuthParagraphs.get(parIndex); | |||
for (int i = 0; i <= restartPosition.getIndex(); i++) { | |||
paragraph.remove(0); | |||
} | |||
Iterator iter = paragraph.iterator(); | |||
while (iter.hasNext() && !((KnuthElement) iter.next()).isBox()) { | |||
iter.remove(); | |||
} | |||
if (!iter.hasNext()) { | |||
knuthParagraphs.remove(parIndex); | |||
} | |||
/* | |||
// get a break point from the list | |||
lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++); | |||
if (iReturnedLBP == breakpoints.size()) { | |||
// return finished when there's no content | |||
if (knuthParagraphs.size() == 0) { | |||
setFinished(true); | |||
return null; | |||
} | |||
BreakPoss curLineBP = new BreakPoss(lbp); | |||
curLineBP.setFlag(BreakPoss.ISLAST, isFinished()); | |||
curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight)); | |||
return curLineBP; | |||
*/ | |||
ipd = context.getRefIPD(); | |||
//PHASE 2: Create line breaks | |||
return createLineBreaks(context.getBPAlignment(), context); | |||
} | |||
/** | |||
@@ -643,22 +626,18 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
private void collectInlineKnuthElements(LayoutContext context) { | |||
LayoutContext inlineLC = new LayoutContext(context); | |||
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 bPrevWasKnuthBox = false; | |||
boolean previousIsBox = false; | |||
StringBuffer trace = new StringBuffer("LineLM:"); | |||
Paragraph lastPar = null; | |||
InlineLevelLayoutManager curLM; | |||
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) { | |||
returnedList = curLM.getNextKnuthElements(inlineLC, effectiveAlignment); | |||
if (returnedList == null | |||
|| returnedList.size() == 0) { | |||
List inlineElements = curLM.getNextKnuthElements(inlineLC, effectiveAlignment); | |||
if (inlineElements == null || inlineElements.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 */ | |||
@@ -666,7 +645,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
} | |||
if (lastPar != null) { | |||
KnuthSequence firstSeq = (KnuthSequence) returnedList.get(0); | |||
KnuthSequence firstSeq = (KnuthSequence) inlineElements.get(0); | |||
// finish last paragraph before a new block sequence | |||
if (!firstSeq.isInlineSequence()) { | |||
@@ -676,7 +655,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
if (log.isTraceEnabled()) { | |||
trace.append(" ]"); | |||
} | |||
bPrevWasKnuthBox = false; | |||
previousIsBox = false; | |||
} | |||
// does the first element of the first paragraph add to an existing word? | |||
@@ -684,27 +663,24 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
KnuthElement thisElement; | |||
thisElement = (KnuthElement) firstSeq.get(0); | |||
if (thisElement.isBox() && !thisElement.isAuxiliary() | |||
&& bPrevWasKnuthBox) { | |||
&& previousIsBox) { | |||
lastPar.addALetterSpace(); | |||
} | |||
} | |||
} | |||
// loop over the KnuthSequences (and single KnuthElements) in returnedList | |||
ListIterator iter = returnedList.listIterator(); | |||
ListIterator iter = inlineElements.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(); | |||
if (lastElement == null) { | |||
throw new NullPointerException( | |||
"Sequence was empty! lastElement is null"); | |||
} | |||
bPrevWasKnuthBox = lastElement.isBox() | |||
&& !((KnuthElement) lastElement).isAuxiliary() | |||
&& ((KnuthElement) lastElement).getW() != 0; | |||
assert lastElement != null; | |||
previousIsBox = 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 | |||
@@ -729,8 +705,7 @@ 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 | |||
@@ -738,7 +713,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(iLineWidth, 0, iLineWidth, null, true)); | |||
lastPar.add(new KnuthGlue(ipd, 0, ipd, null, true)); | |||
} | |||
lastPar.endParagraph(); | |||
ElementListObserver.observe(lastPar, "line", null); | |||
@@ -746,7 +721,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
if (log.isTraceEnabled()) { | |||
trace.append(" ]"); | |||
} | |||
bPrevWasKnuthBox = false; | |||
previousIsBox = false; | |||
} | |||
} else { // the sequence is a block sequence | |||
// the positions will be wrapped with this LM in postProcessLineBreaks | |||
@@ -767,134 +742,6 @@ 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 | |||
@@ -902,10 +749,8 @@ 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()) { | |||
@@ -947,7 +792,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
this); | |||
if (hyphenationProperties.hyphenate.getEnum() == EN_TRUE | |||
&& fobj.getWrapOption() != EN_NO_WRAP) { | |||
&& fobj.getWrapOption() != EN_NO_WRAP && !hyphenationPerformed) { | |||
hyphenationPerformed = true; | |||
findHyphenationPoints(currPar); | |||
} | |||
@@ -958,7 +804,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
} else { | |||
allowedBreaks = BreakingAlgorithm.NO_FLAGGED_PENALTIES; | |||
} | |||
alg.setConstantLineWidth(iLineWidth); | |||
alg.setConstantLineWidth(ipd); | |||
iBPcount = alg.findBreakingPoints(currPar, | |||
maxAdjustment, false, allowedBreaks); | |||
if (iBPcount == 0 || alignment == EN_JUSTIFY) { | |||
@@ -1014,26 +860,26 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
alg.resetAlgorithm(); | |||
lineLayouts.savePossibilities(true); | |||
// try with shorter lines | |||
int savedLineWidth = iLineWidth; | |||
iLineWidth = (int) (iLineWidth * 0.95); | |||
int savedLineWidth = ipd; | |||
ipd = (int) (ipd * 0.95); | |||
iBPcount = alg.findBreakingPoints(currPar, | |||
maxAdjustment, true, allowedBreaks); | |||
maxAdjustment, true, allowedBreaks); | |||
// use normal lines, when possible | |||
lineLayouts.restorePossibilities(); | |||
iLineWidth = savedLineWidth; | |||
ipd = savedLineWidth; | |||
} | |||
if (!lineLayouts.canUseLessLines()) { | |||
alg.resetAlgorithm(); | |||
lineLayouts.savePossibilities(true); | |||
// try with longer lines | |||
int savedLineWidth = iLineWidth; | |||
iLineWidth = (int) (iLineWidth * 1.05); | |||
alg.setConstantLineWidth(iLineWidth); | |||
int savedLineWidth = ipd; | |||
ipd = (int) (ipd * 1.05); | |||
alg.setConstantLineWidth(ipd); | |||
iBPcount = alg.findBreakingPoints(currPar, | |||
maxAdjustment, true, allowedBreaks); | |||
// use normal lines, when possible | |||
lineLayouts.restorePossibilities(); | |||
iLineWidth = savedLineWidth; | |||
ipd = savedLineWidth; | |||
} | |||
//log.debug("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines()); | |||
//log.debug(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines()); | |||
@@ -1052,6 +898,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
List returnList = new LinkedList(); | |||
int endIndex = -1; | |||
for (int p = 0; p < knuthParagraphs.size(); p++) { | |||
// penalty between paragraphs | |||
if (p > 0) { | |||
@@ -1089,7 +936,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
} else { | |||
/* "normal" vertical alignment: create a sequence whose boxes | |||
represent effective lines, and contain LineBreakPositions */ | |||
Position returnPosition = new LeafPosition(this, p); | |||
int startIndex = 0; | |||
for (int i = 0; | |||
i < llPoss.getChosenLineCount(); | |||
@@ -1101,13 +947,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
// penalty allowing a page break between lines | |||
Keep keep = getKeepTogether(); | |||
returnList.add(new BreakElement( | |||
new Position(this), | |||
new LeafPosition(this, p, endIndex), | |||
keep.getPenalty(), | |||
keep.getContext(), | |||
context)); | |||
} | |||
int endIndex | |||
= ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); | |||
endIndex = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); | |||
// create a list of the FootnoteBodyLM handling footnotes | |||
// whose citations are in this line | |||
List footnoteList = new LinkedList(); | |||
@@ -1115,15 +960,14 @@ 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)); | |||
@@ -1597,7 +1441,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
Position pos = (Position) parentIter.next(); | |||
boolean isLastPosition = !parentIter.hasNext(); | |||
if (pos instanceof LineBreakPosition) { | |||
addInlineArea(context, pos, isLastPosition); | |||
addInlineArea(context, (LineBreakPosition) pos, isLastPosition); | |||
} else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) { | |||
addBlockArea(context, pos, isLastPosition); | |||
} else { | |||
@@ -1617,147 +1461,129 @@ 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, 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)); | |||
} | |||
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)); | |||
} | |||
} | |||
// 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 | |||
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(); | |||
// 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(); | |||
} | |||
} | |||
} | |||
// 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 | |||
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, iStartElement, iEndElement + 1); | |||
iStartElement = lbp.getLeafPos() + 1; | |||
if (iStartElement == seq.size()) { | |||
// advance to next paragraph | |||
iStartElement = 0; | |||
// ignore KnuthGlue and KnuthPenalty objects | |||
// at the beginning of the line | |||
ListIterator seqIterator = seq.listIterator(startElementIndex); | |||
while (seqIterator.hasNext() && !((KnuthElement) seqIterator.next()).isBox()) { | |||
startElementIndex++; | |||
} | |||
} | |||
// 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.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)); | |||
} | |||
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); | |||
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)); | |||
/* | |||
* 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; | |||
} | |||
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)); | |||
} | |||
// 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); | |||
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)); | |||
} | |||
// 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); | |||
} | |||
/** | |||
@@ -1800,7 +1626,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
// set last area flag | |||
blocklc.setFlags(LayoutContext.LAST_AREA, | |||
(context.isLastArea() && childLM == lastLM)); | |||
blocklc.setStackLimitsFrom(context); | |||
blocklc.setStackLimitBP(context.getStackLimitBP()); | |||
// Add the line areas to Area | |||
childLM.addAreas(childPosIter, blocklc); | |||
blocklc.setLeadingSpace(blocklc.getTrailingSpace()); | |||
@@ -1841,5 +1667,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager | |||
public boolean getGeneratesLineArea() { | |||
return true; | |||
} | |||
/** {@inheritDoc} */ | |||
public boolean isRestartable() { | |||
return true; | |||
} | |||
} | |||
@@ -702,6 +702,13 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
public void reset() { | |||
super.reset(); | |||
label.reset(); | |||
body.reset(); | |||
} | |||
} | |||
@@ -1,3 +1,4 @@ | |||
<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en"> | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<catalogue xml:lang="en"> | |||
<message key="org.apache.fop.render.pdf.PDFEventProducer.nonFullyResolvedLinkTargets">{count} link target{count,equals,1,,s} could not be fully resolved and now point{count,equals,1,,s} to the top of the page or {count,equals,1,is,are} dysfunctional.</message> | |||
</catalogue> |
@@ -0,0 +1,97 @@ | |||
<?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 that blocks of texts are re-laid out after a change of the flow ipd. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body" language="en" hyphenate="true"> | |||
<fo:block text-align="justify" id="surrounding" | |||
space-before.minimum="10pt" | |||
space-before.optimum="12pt" | |||
space-before.maximum="50pt"> | |||
<fo:block space-before="inherit" id="b1">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b2">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b3" border-top="1pt solid black" | |||
border-before-width.conditionality="retain">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face. In olden times when wishing still helped one, there lived a king | |||
whose daughters were all beautiful, but the youngest was so beautiful that the sun | |||
itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
<fo:block space-before="inherit" id="b4" border-top="1pt solid black">In olden times | |||
when wishing still helped one, there lived a king whose daughters were all beautiful, | |||
but the youngest was so beautiful that the sun itself, which has seen so much, was | |||
astonished whenever it shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b5">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="13100" xpath="//pageViewport[1]//flow/block/block[2]/@space-before"/> | |||
<eval expected="13100" xpath="//pageViewport[1]//flow/block/block[3]/@space-before"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[1]//flow/block/block[3]/@border-before"/> | |||
<eval expected="In" xpath="//pageViewport[1]//flow/block/block[3]/lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/@ipd"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block[1]/@border-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/@ipd"/> | |||
<eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[1]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block[2]/@space-before"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block[2]/@border-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/@ipd"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block[3]/@space-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/lineArea[1]/@ipd"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,75 @@ | |||
<?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 that blocks of texts are re-laid out after a change of the flow ipd. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block id="b1">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face.</fo:block> | |||
<fo:block id="b2">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face.</fo:block> | |||
<fo:block id="b3">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face. In olden times | |||
when wishing still helped one, there lived a king whose daughters were all beautiful, | |||
but the youngest was so beautiful that the sun itself, which has seen so much, was | |||
astonished whenever it shone in her face.</fo:block> | |||
<fo:block id="b4">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face.</fo:block> | |||
<fo:block id="b5">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="has" xpath="//pageViewport[1]//flow/block[3]/lineArea[3]/text/word[position()=last()]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[1]/lineArea[1]/@ipd"/> | |||
<eval expected="seen" xpath="//pageViewport[2]//flow/block[1]/lineArea[1]/text/word[1]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[2]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[2]/lineArea[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[3]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block[3]/lineArea[1]/@ipd"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,86 @@ | |||
<?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 that a change of IPD between two blocks is correctly handled. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block text-align="justify" id="surrounding" | |||
space-before.minimum="10pt" | |||
space-before.optimum="12pt" | |||
space-before.maximum="50pt"> | |||
<fo:block space-before="inherit" id="b1">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b2">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b3">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block border-top="1pt solid black" space-before.minimum="10pt" | |||
space-before.optimum="12pt" space-before.maximum="50pt" | |||
space-before.conditionality="retain" id="b4">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b5">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="face." xpath="//pageViewport[1]//flow/block/block[3]/lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block[1]/@space-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/@ipd"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block[1]/@border-before"/> | |||
<eval expected="In" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[2]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,159 @@ | |||
<?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 that non-restartable elements still show up at IPD change, even if not | |||
re-laid out. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body" text-align="justify"> | |||
<fo:block space-before="10pt" id="b1_1">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
<fo:block space-before="10pt" id="b1_2">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
<fo:table table-layout="fixed" width="100%" border="1pt solid black" space-before="10pt" | |||
padding="2pt" border-collapse="separate"> | |||
<fo:table-body> | |||
<fo:table-row> | |||
<fo:table-cell> | |||
<fo:block space-before="10pt" id="b1_3">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was | |||
so beautiful that the sun itself, which has seen so much, was astonished | |||
whenever it shone in her face.</fo:block> | |||
<fo:block space-before="10pt" id="b1_4">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was | |||
so beautiful that the sun itself, which has seen so much, was astonished | |||
whenever it shone in her face.</fo:block> | |||
</fo:table-cell> | |||
</fo:table-row> | |||
</fo:table-body> | |||
</fo:table> | |||
<fo:block space-before="10pt" id="b1_5" border-top="1pt solid red">In olden times when | |||
wishing still helped one, there lived a king whose daughters were all beautiful, but the | |||
youngest was so beautiful that the sun itself, which has seen so much, was astonished | |||
whenever it shone in her face.</fo:block> | |||
<fo:block space-before="10pt" id="b1_6">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body" text-align="justify"> | |||
<fo:block space-before="10pt" id="b2_1">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
<fo:block space-before="10pt" id="b2_2">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
<fo:list-block space-before="10pt" provisional-distance-between-starts="0.5cm"> | |||
<fo:list-item> | |||
<fo:list-item-label end-indent="label-end()"> | |||
<fo:block start-indent="2pt">•</fo:block> | |||
</fo:list-item-label> | |||
<fo:list-item-body start-indent="body-start()"> | |||
<fo:block space-before="10pt" id="b2_3">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was | |||
so beautiful that the sun itself, which has seen so much, was | |||
astonished…</fo:block> | |||
</fo:list-item-body> | |||
</fo:list-item> | |||
<fo:list-item> | |||
<fo:list-item-label end-indent="label-end()"> | |||
<fo:block start-indent="2pt">•</fo:block> | |||
</fo:list-item-label> | |||
<fo:list-item-body start-indent="body-start()"> | |||
<fo:block id="b2_4">In olden times when wishing still helped one, there lived a king | |||
whose daughters were all beautiful, but the youngest was so beautiful that the sun | |||
itself, which has seen so much, was astonished…</fo:block> | |||
</fo:list-item-body> | |||
</fo:list-item> | |||
</fo:list-block> | |||
<fo:block space-before="10pt" space-before.conditionality="retain" border-top="1pt solid | |||
red" id="b2_5">In olden times when wishing still helped one, there lived a king whose | |||
daughters were all beautiful, but the youngest was so beautiful that the sun itself, | |||
which has seen so much, was astonished whenever it shone in her face.</fo:block> | |||
<fo:block space-before="10pt" id="b2_6">In olden times when wishing still helped one, there | |||
lived a king whose daughters were all beautiful, but the youngest was so beautiful that | |||
the sun itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<!-- First page sequence – table --> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]/@border-after"/> | |||
<eval expected="300000" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/@ipd"/> | |||
<eval expected="b1_4" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]/block/block/@prod-id"/> | |||
<eval expected="In" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/text/word[2]"/> | |||
<eval expected="her" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[4]/text/word[position()=last()-1]"/> | |||
<eval expected="face." xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="b1_5" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@prod-id"/> | |||
<eval expected="500000" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@ipd"/> | |||
<eval expected="(solid,#ff0000,1000)" | |||
xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@border-before"/> | |||
<eval expected="In" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[2]"/> | |||
<!-- Second page sequence – list --> | |||
<eval expected="300000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/@ipd"/> | |||
<eval expected="b2_4" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/@prod-id"/> | |||
<eval expected="In" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[1]/text/word[2]"/> | |||
<eval expected="was" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[4]/text/word[position()=last()-1]"/> | |||
<eval expected="astonished…" | |||
xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="b2_5" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@prod-id"/> | |||
<eval expected="500000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@ipd"/> | |||
<eval expected="10000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@space-before"/> | |||
<eval expected="(solid,#ff0000,1000)" | |||
xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@border-before"/> | |||
<eval expected="In" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[2]"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,101 @@ | |||
<?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 that block-container elements correctly support an IPD change. | |||
</p> | |||
<!-- NOTE: This test case is a copy of flow_changing-ipd_1.xml, modified to simply surround | |||
block 3 with a block-container. --> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block text-align="justify" id="surrounding" | |||
space-before.minimum="10pt" | |||
space-before.optimum="12pt" | |||
space-before.maximum="50pt"> | |||
<fo:block space-before="inherit" id="b1">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b2">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block-container space-before="inherit"> | |||
<fo:block id="b3" border-top="1pt solid black" | |||
border-before-width.conditionality="retain">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face. In olden times when wishing still helped one, there lived a king | |||
whose daughters were all beautiful, but the youngest was so beautiful that the sun | |||
itself, which has seen so much, was astonished whenever it shone in her | |||
face.</fo:block> | |||
</fo:block-container> | |||
<fo:block space-before="inherit" id="b4" border-top="1pt solid black">In olden times | |||
when wishing still helped one, there lived a king whose daughters were all beautiful, | |||
but the youngest was so beautiful that the sun itself, which has seen so much, was | |||
astonished whenever it shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b5">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
</fo:block> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="13100" xpath="//pageViewport[1]//flow/block/block[2]/@space-before"/> | |||
<eval expected="13100" xpath="//pageViewport[1]//flow/block/block[3]/@space-before"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[1]//flow/block/block[3]/block/block/@border-before"/> | |||
<eval expected="In" xpath="//pageViewport[1]//flow/block/block[3]/block/block/lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/@ipd"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block[1]/block/block/@border-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/block/block/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/block/block/lineArea[1]/@ipd"/> | |||
<eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/block/block/lineArea[1]/text/word[1]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block[2]/@space-before"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block[2]/@border-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/@ipd"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block[3]/@space-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/lineArea[1]/@ipd"/> | |||
</checks> | |||
</testcase> |
@@ -0,0 +1,89 @@ | |||
<?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 that a change of IPD between two blocks surrounded by a block-container is | |||
correctly handled. | |||
</p> | |||
<!-- NOTE: This test case is a copy of flow_changing-ipd_3.xml, with the surrounding block | |||
replaced with a block-container. --> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="narrow" | |||
page-height="300pt" page-width="400pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:simple-page-master master-name="wide" | |||
page-height="300pt" page-width="600pt" margin="50pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
<fo:page-sequence-master master-name="pages"> | |||
<fo:single-page-master-reference master-reference="narrow"/> | |||
<fo:repeatable-page-master-reference master-reference="wide"/> | |||
</fo:page-sequence-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="pages"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:block-container text-align="justify" id="surrounding" | |||
space-before.minimum="10pt" | |||
space-before.optimum="12pt" | |||
space-before.maximum="50pt"> | |||
<fo:block space-before="inherit" id="b1">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b2">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b3">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block border-top="1pt solid black" space-before.minimum="10pt" | |||
space-before.optimum="12pt" space-before.maximum="50pt" | |||
space-before.conditionality="retain" id="b4">In olden times when wishing still helped | |||
one, there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
<fo:block space-before="inherit" id="b5">In olden times when wishing still helped one, | |||
there lived a king whose daughters were all beautiful, but the youngest was so | |||
beautiful that the sun itself, which has seen so much, was astonished whenever it | |||
shone in her face.</fo:block> | |||
</fo:block-container> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<eval expected="face." xpath="//pageViewport[1]//flow/block/block/block[3]/lineArea[4]/text/word[position()=last()]"/> | |||
<eval expected="12000" xpath="//pageViewport[2]//flow/block/block/block[1]/@space-before"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[1]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/@ipd"/> | |||
<eval expected="(solid,#000000,1000)" | |||
xpath="//pageViewport[2]//flow/block/block/block[1]/@border-before"/> | |||
<eval expected="In" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/text/word[1]"/> | |||
<eval expected="olden" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/text/word[2]"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[2]/@ipd"/> | |||
<eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[2]/lineArea[1]/@ipd"/> | |||
</checks> | |||
</testcase> |