return (blockLists.size() == 0);
}
- protected void startPart(BlockSequence list, boolean bIsFirstPage) {
+ protected void startPart(BlockSequence list, int breakClass) {
//nop
}
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
getPageViewportProvider(),
alignment, alignmentLast, footnoteSeparatorLength);
- int iOptPageNumber;
+ int iOptPageCount;
BlockSequence effectiveList;
if (alignment == Constants.EN_JUSTIFY) {
effectiveList = blockList;
}
- //iOptPageNumber = alg.firstFit(effectiveList, flowBPD, 1, true);
+ //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
alg.setConstantLineWidth(flowBPD);
- iOptPageNumber = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
- 1, true, true);
- log.debug("PLM> iOptPageNumber= " + iOptPageNumber
+ iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
+ 1, true, true);
+ log.debug("PLM> iOptPageCount= " + iOptPageCount
+ " pageBreaks.size()= " + alg.getPageBreaks().size());
//*** Phase 3: Add areas ***
- doPhase3(alg, iOptPageNumber, blockList, effectiveList);
+ doPhase3(alg, iOptPageCount, blockList, effectiveList);
}
}
int endElementIndex = 0;
for (int p = 0; p < partCount; p++) {
PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(p);
- endElementIndex = pbp.getLeafPos();
- log.debug("PLM> part: " + (p + 1)
- + ", break at position " + endElementIndex);
- startPart(effectiveList, (p == 0));
-
- int displayAlign = getCurrentDisplayAlign();
+ //Check the last break position for forced breaks
+ int lastBreakClass;
+ if (p == 0) {
+ lastBreakClass = effectiveList.getStartOn();
+ } else {
+ KnuthElement lastBreakElement = effectiveList.getElement(endElementIndex);
+ if (lastBreakElement.isPenalty()) {
+ KnuthPenalty pen = (KnuthPenalty)lastBreakElement;
+ lastBreakClass = pen.getBreakClass();
+ } else {
+ lastBreakClass = Constants.EN_AUTO;
+ }
+ }
+ //the end of the new part
+ endElementIndex = pbp.getLeafPos();
+
// ignore the first elements added by the
// PageSequenceLayoutManager
startElementIndex += (startElementIndex == 0)
? effectiveList.ignoreAtStart
: 0;
+ log.debug("PLM> part: " + (p + 1)
+ + ", start at pos " + startElementIndex
+ + ", break at pos " + endElementIndex);
+
+ startPart(effectiveList, lastBreakClass);
+
+ int displayAlign = getCurrentDisplayAlign();
+
// ignore the last elements added by the
// PageSequenceLayoutManager
endElementIndex -= (endElementIndex == (originalList.size() - 1))
breakBefore = ((org.apache.fop.fo.flow.Block) fobj).getBreakBefore();
} else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
breakBefore = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakBefore();
+ } else if (fobj instanceof org.apache.fop.fo.flow.Table) {
+ breakBefore = ((org.apache.fop.fo.flow.Table) fobj).getBreakBefore();
}
if (breakBefore == EN_PAGE
|| breakBefore == EN_COLUMN
breakAfter = ((org.apache.fop.fo.flow.Block) fobj).getBreakAfter();
} else if (fobj instanceof org.apache.fop.fo.flow.BlockContainer) {
breakAfter = ((org.apache.fop.fo.flow.BlockContainer) fobj).getBreakAfter();
+ } else if (fobj instanceof org.apache.fop.fo.flow.Table) {
+ breakAfter = ((org.apache.fop.fo.flow.Table) fobj).getBreakAfter();
}
if (breakAfter == EN_PAGE
|| breakAfter == EN_COLUMN
addAreas(alg, partCount, originalList, effectiveList);
}
- protected void startPart(BlockSequence list, boolean bIsFirstPage) {
+ protected void startPart(BlockSequence list, int breakClass) {
if (curPV == null) {
throw new IllegalStateException("curPV must not be null");
} else {
// the current BlockSequence, it could have a break
// condition that must be satisfied;
// otherwise, we may simply need a new page
- handleBreakTrait(bIsFirstPage ? list.getStartOn() : Constants.EN_PAGE);
+ handleBreakTrait(breakClass);
}
}
pvProvider.setStartPageOfNextElementList(currentPageNum);
import java.util.Iterator;
import java.util.List;
+import org.apache.fop.fo.flow.TableRow;
import org.apache.fop.traits.MinOptMax;
/**
return this.bodyType;
}
+ /** @return the table-row FO for this EffRow, or null if there is no table-row. */
+ public TableRow getTableRow() {
+ return getGridUnit(0).getRow();
+ }
+
/** @return the calculated height for this EffRow. */
public MinOptMax getHeight() {
return this.height;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Block;
import org.apache.fop.area.Trait;
+import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableBody;
import org.apache.fop.fo.flow.TableRow;
private LinkedList footerList;
private int headerNetHeight = 0;
private int footerNetHeight = 0;
+ private boolean firstBreakBeforeServed = false;
private int startXOffset;
private int usedBPD;
KnuthBox headerAsFirst = null;
KnuthBox headerAsSecondToLast = null;
KnuthBox footerAsLast = null;
- if (headerIter != null) {
+ if (headerIter != null && headerList == null) {
this.headerList = getKnuthElementsForRowIterator(
headerIter, context, alignment, TableRowIterator.HEADER);
ElementListUtils.removeLegalBreaks(this.headerList);
headerAsSecondToLast = box;
}
}
- if (footerIter != null) {
+ if (footerIter != null && footerList == null) {
this.footerList = getKnuthElementsForRowIterator(
footerIter, context, alignment, TableRowIterator.FOOTER);
ElementListUtils.removeLegalBreaks(this.footerList);
LinkedList returnList = new LinkedList();
EffRow[] rowGroup = null;
while ((rowGroup = iter.getNextRowGroup()) != null) {
+ //Check for break-before on the table-row at the start of the row group
+ TableRow rowFO = rowGroup[0].getTableRow();
+ if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
+ log.info("break-before found");
+ if (returnList.size() > 0) {
+ KnuthElement last = (KnuthElement)returnList.getLast();
+ if (last.isPenalty()) {
+ KnuthPenalty pen = (KnuthPenalty)last;
+ pen.setP(-KnuthPenalty.INFINITE);
+ pen.setBreakClass(rowFO.getBreakBefore());
+ }
+ } else {
+ if (!firstBreakBeforeServed) {
+ returnList.add(new KnuthPenalty(0, -KnuthPenalty.INFINITE,
+ false, rowFO.getBreakBefore(), new Position(getTableLM()), true));
+ iter.backToPreviousRow();
+ firstBreakBeforeServed = true;
+ break;
+ }
+ }
+ }
+ firstBreakBeforeServed = true;
+
+ //Border resolution
if (!isSeparateBorderModel()) {
resolveNormalBeforeAfterBordersForRowGroup(rowGroup, iter);
}
+
+ //Element list creation
createElementsForRowGroup(context, alignment, bodyType,
returnList, rowGroup);
+
+ //Handle keeps
if (context.isKeepWithNextPending()) {
log.debug("child LM (row group) signals pending keep-with-next");
}
KnuthElement last = (KnuthElement)returnList.getLast();
if (last.isPenalty()) {
KnuthPenalty pen = (KnuthPenalty)last;
- pen.setP(KnuthPenalty.INFINITE);
+ //Only honor keep if there's no forced break
+ if (!pen.isForcedBreak()) {
+ pen.setP(KnuthPenalty.INFINITE);
+ }
+ }
+ }
+ }
+
+ //Check for break-after on the table-row at the end of the row group
+ rowFO = rowGroup[rowGroup.length - 1].getTableRow();
+ if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
+ log.info("break-after found");
+ if (returnList.size() > 0) {
+ KnuthElement last = (KnuthElement)returnList.getLast();
+ if (last.isPenalty()) {
+ KnuthPenalty pen = (KnuthPenalty)last;
+ pen.setP(-KnuthPenalty.INFINITE);
+ pen.setBreakClass(rowFO.getBreakAfter());
}
}
}
//Remove last penalty
KnuthElement last = (KnuthElement)returnList.getLast();
if (last.isPenalty()) {
- returnList.removeLast();
+ KnuthPenalty pen = (KnuthPenalty)last;
+ if (!pen.isForcedBreak()) {
+ //Only remove if we don't signal a forced break
+ returnList.removeLast();
+ }
}
}
return returnList;
//Get the element list for the cell contents
LinkedList elems = primary.getCellLM().getNextKnuthElements(
childLC, alignment);
- primary.setElements(elems);
+ //Temporary? Multiple calls in case of break conditions.
+ //TODO Revisit when table layout is restartable
+ while (!primary.getCellLM().isFinished()) {
+ LinkedList additionalElems = primary.getCellLM().getNextKnuthElements(
+ childLC, alignment);
+ elems.addAll(additionalElems);
+ }
ElementListObserver.observe(elems, "table-cell", primary.getCell().getId());
+
+ if (((KnuthElement)elems.getLast()).isPenalty()
+ && ((KnuthPenalty)elems.getLast()).getP()
+ == -KnuthElement.INFINITE) {
+ // a descendant of this block has break-after
+ log.warn("Descendant of table-cell signals break: "
+ + primary.getCellLM().isFinished());
+ }
+
+ primary.setElements(elems);
if (childLC.isKeepWithNextPending()) {
log.debug("child LM signals pending keep-with-next");
return iIndents;
}
- /**
- * @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
- */
+ /** @see org.apache.fop.layoutmgr.LayoutManager */
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
- //Body curLM; // currently active LM
+ LinkedList returnList = new LinkedList();
+
+ if (!bBreakBeforeServed) {
+ try {
+ if (addKnuthElementsForBreakBefore(returnList)) {
+ return returnList;
+ }
+ } finally {
+ bBreakBeforeServed = true;
+ }
+ }
referenceIPD = context.getRefIPD();
if (fobj.getInlineProgressionDimension().getOptimum().getEnum() != EN_AUTO) {
LinkedList returnedList = null;
LinkedList contentList = new LinkedList();
- LinkedList returnList = new LinkedList();
//Position returnPosition = new NonLeafPosition(this, null);
//Body prevLM = null;
stackSize));
childLC.setRefIPD(context.getRefIPD());
- contentLM = new TableContentLayoutManager(this);
+ if (contentLM == null) {
+ contentLM = new TableContentLayoutManager(this);
+ }
returnedList = contentLM.getNextKnuthElements(childLC, alignment);
if (childLC.isKeepWithNextPending()) {
log.debug("TableContentLM signals pending keep-with-next");
}
}
wrapPositionElements(contentList, returnList);
+ addKnuthElementsForBreakAfter(returnList);
setFinished(true);
return returnList;
}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.flow.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KnuthBox;
private int[] borderAfter;
private boolean rowBacktrackForLastStep;
private boolean[] keepWithNextSignals;
+ private boolean[] forcedBreaks;
/**
* Main constructor
borderBefore = new int[columnCount];
borderAfter = new int[columnCount];
keepWithNextSignals = new boolean[columnCount];
+ forcedBreaks = new boolean[columnCount];
Arrays.fill(end, -1);
}
+ private void clearBreakCondition() {
+ Arrays.fill(forcedBreaks, false);
+ }
+
+ private boolean isBreakCondition() {
+ for (int i = 0; i < forcedBreaks.length; i++) {
+ if (forcedBreaks[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private EffRow getActiveRow() {
return rowGroup[activeRow];
}
widths[column] = 0;
startRow[column] = activeRow;
keepWithNextSignals[column] = false;
+ forcedBreaks[column] = false;
} else if (gu.isPrimary()) {
PrimaryGridUnit pgu = (PrimaryGridUnit)gu;
boolean makeBoxForWholeRow = false;
widths[column] = 0;
startRow[column] = activeRow;
keepWithNextSignals[column] = false;
+ forcedBreaks[column] = false;
}
}
if (signalKeepWithNext || getTableLM().mustKeepTogether()) {
p = KnuthPenalty.INFINITE;
}
+ if (isBreakCondition()) {
+ p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
+ clearBreakCondition();
+ }
returnList.add(new KnuthPenalty(effPenaltyLen, p, false, penaltyPos, false));
log.debug("step=" + step + " (+" + increase + ")"
//we have to signal the still pending last keep-with-next using the LayoutContext.
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
}
+ if (isBreakCondition()) {
+ ((KnuthPenalty)returnList.getLast()).setP(-KnuthPenalty.INFINITE);
+ }
lastTCPos.setFlag(TableContentPosition.LAST_IN_ROWGROUP, true);
return returnList;
}
private int getNextStep(int lastStep) {
+ //Check for forced break conditions
+ /*
+ if (isBreakCondition()) {
+ return -1;
+ }*/
+
int[] backupWidths = new int[start.length];
System.arraycopy(widths, 0, backupWidths, 0, backupWidths.length);
if (rowPendingIndicator == 0) {
if (activeRow < rowGroup.length - 1) {
+ TableRow rowFO = getActiveRow().getTableRow();
+ if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
+ log.warn("break-after ignored on table-row because of row spanning "
+ + "in progress (See XSL 1.0, 7.19.1)");
+ }
activeRow++;
log.debug("===> new row: " + activeRow);
initializeElementLists();
backupWidths[i] = 0;
}
}
+ rowFO = getActiveRow().getTableRow();
+ if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
+ log.warn("break-before ignored on table-row because of row spanning "
+ + "in progress (See XSL 1.0, 7.19.2)");
+ }
}
}
end[i]++;
KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
if (el.isPenalty()) {
- if (el.getP() < KnuthElement.INFINITE) {
+ if (el.getP() <= -KnuthElement.INFINITE) {
+ log.warn("FORCED break encountered!");
+ forcedBreaks[i] = true;
+ break;
+ } else if (el.getP() < KnuthElement.INFINITE) {
//First legal break point
break;
}