Browse Source

Merged back ChangingIPDHack branch into Trunk


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@808157 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Vincent Hennebert 15 years ago
parent
commit
bcfda76c15
32 changed files with 1945 additions and 816 deletions
  1. 20
    0
      src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
  2. 129
    17
      src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
  3. 33
    7
      src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
  4. 5
    0
      src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
  5. 1
    1
      src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
  6. 306
    0
      src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  7. 25
    11
      src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
  8. 282
    120
      src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  9. 14
    7
      src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
  10. 133
    86
      src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  11. 4
    12
      src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
  12. 1
    38
      src/java/org/apache/fop/layoutmgr/LayoutContext.java
  13. 33
    0
      src/java/org/apache/fop/layoutmgr/LayoutManager.java
  14. 8
    3
      src/java/org/apache/fop/layoutmgr/LeafPosition.java
  15. 34
    1
      src/java/org/apache/fop/layoutmgr/PageBreaker.java
  16. 62
    0
      src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
  17. 27
    0
      src/java/org/apache/fop/layoutmgr/PageProvider.java
  18. 5
    0
      src/java/org/apache/fop/layoutmgr/Position.java
  19. 5
    1
      src/java/org/apache/fop/layoutmgr/SpaceResolver.java
  20. 1
    102
      src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  21. 3
    7
      src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
  22. 0
    10
      src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
  23. 3
    29
      src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
  24. 195
    363
      src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
  25. 7
    0
      src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
  26. 2
    1
      src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
  27. 97
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_1.xml
  28. 75
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_2.xml
  29. 86
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_3.xml
  30. 159
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_4.xml
  31. 101
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml
  32. 89
    0
      test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml

+ 20
- 0
src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java View File

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

}

+ 129
- 17
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java View File

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

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

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

/** Parent LayoutManager for this LayoutManager */
protected LayoutManager parentLM = 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;
}

}

+ 5
- 0
src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java View File

@@ -382,4 +382,9 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa
}
}

/** {@inheritDoc} */
public void reset() {
throw new IllegalStateException();
}

}

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

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


+ 306
- 0
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java View File

@@ -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;


+ 25
- 11
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java View File

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

}


+ 282
- 120
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -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
}

}


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

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

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

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

}


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

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

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

@@ -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"

+ 33
- 0
src/java/org/apache/fop/layoutmgr/LayoutManager.java View File

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

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

@@ -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() {

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

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

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

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

}

+ 27
- 0
src/java/org/apache/fop/layoutmgr/PageProvider.java View File

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

+ 5
- 0
src/java/org/apache/fop/layoutmgr/Position.java View File

@@ -28,6 +28,11 @@ public class Position {
layoutManager = lm;
}

public Position(LayoutManager lm, int index) {
this(lm);
setIndex(index);
}

public LayoutManager getLM() {
return layoutManager;
}

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

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

}

/**

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

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

/**

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

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


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

@@ -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:");

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

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

+ 195
- 363
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java View File

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

}


+ 7
- 0
src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java View File

@@ -702,6 +702,13 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}
}

/** {@inheritDoc} */
public void reset() {
super.reset();
label.reset();
body.reset();
}


}


+ 2
- 1
src/java/org/apache/fop/render/pdf/PDFEventProducer.xml View File

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

+ 97
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_1.xml View File

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

+ 75
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_2.xml View File

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

+ 86
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_3.xml View File

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

+ 159
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_4.xml View File

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

+ 101
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml View File

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

+ 89
- 0
test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml View File

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

Loading…
Cancel
Save