diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2008-02-13 18:11:06 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2008-02-13 18:11:06 +0000 |
commit | 71ecb950fba8d7134c912acda3a75845930099cb (patch) | |
tree | ed9a24ff0a999ae534c2757f3845bb8bc8d41ac6 /src/java/org/apache/fop | |
parent | ea691f9d34c8b1757f36f2dcecf520b3ffe3e27e (diff) | |
download | xmlgraphics-fop-71ecb950fba8d7134c912acda3a75845930099cb.tar.gz xmlgraphics-fop-71ecb950fba8d7134c912acda3a75845930099cb.zip |
Added support for breaks before and after table cells
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@627553 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop')
10 files changed, 208 insertions, 60 deletions
diff --git a/src/java/org/apache/fop/fo/flow/table/EffRow.java b/src/java/org/apache/fop/fo/flow/table/EffRow.java index fb2162e55..ac99a1d37 100644 --- a/src/java/org/apache/fop/fo/flow/table/EffRow.java +++ b/src/java/org/apache/fop/fo/flow/table/EffRow.java @@ -22,8 +22,10 @@ package org.apache.fop.fo.flow.table; import java.util.Iterator; import java.util.List; +import org.apache.fop.fo.Constants; import org.apache.fop.layoutmgr.table.TableRowIterator; import org.apache.fop.traits.MinOptMax; +import org.apache.fop.util.BreakUtil; /** * This class represents an effective row in a table and holds a list of grid units occupying @@ -159,7 +161,50 @@ public class EffRow { throw new IllegalArgumentException("Illegal flag queried: " + which); } } - + + + /** + * Returns the break class for this row. This is a combination of break-before set on + * the first children of any cells starting on this row. + * <p><strong>Note:</strong> this works only after getNextKuthElements on the + * corresponding TableCellLM have been called!</p> + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link + * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} + */ + public int getBreakBefore() { + int breakBefore = Constants.EN_AUTO; + for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (gu.isPrimary()) { + breakBefore = BreakUtil.compareBreakClasses(breakBefore, + gu.getPrimary().getBreakBefore()); + } + } + return breakBefore; + } + + /** + * Returns the break class for this row. This is a combination of break-after set on + * the last children of any cells ending on this row. + * <p><strong>Note:</strong> this works only after getNextKuthElements on the + * corresponding TableCellLM have been called!</p> + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link + * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} + */ + public int getBreakAfter() { + int breakAfter = Constants.EN_AUTO; + for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (gu.isPrimary()) { + breakAfter = BreakUtil.compareBreakClasses(breakAfter, + gu.getPrimary().getBreakAfter()); + } + } + return breakAfter; + } + /** {@inheritDoc} */ public String toString() { StringBuffer sb = new StringBuffer("EffRow {"); diff --git a/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java index ac793f889..583abcaa3 100644 --- a/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java @@ -52,7 +52,7 @@ public class EmptyGridUnit extends GridUnit { /** {@inheritDoc} */ public boolean isPrimary() { - return true; + return false; } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java index cff3c2ac1..c95f3f8c3 100644 --- a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java @@ -22,6 +22,7 @@ package org.apache.fop.fo.flow.table; import java.util.LinkedList; import java.util.List; +import org.apache.fop.fo.Constants; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.table.TableCellLayoutManager; @@ -51,6 +52,9 @@ public class PrimaryGridUnit extends GridUnit { private boolean isSeparateBorderModel; private int halfBorderSeparationBPD; + private int breakBefore = Constants.EN_AUTO; + private int breakAfter = Constants.EN_AUTO; + /** * Creates a new primary grid unit. * @@ -320,4 +324,42 @@ public class PrimaryGridUnit extends GridUnit { cellLM = new TableCellLayoutManager(cell, this); } + /** + * Returns the class of the before break for the first child element of this cell. + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link + * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} + */ + public int getBreakBefore() { + return breakBefore; + } + + /** + * Don't use, reserved for TableCellLM. TODO + * + * @param breakBefore the breakBefore to set + */ + public void setBreakBefore(int breakBefore) { + this.breakBefore = breakBefore; + } + + /** + * Returns the class of the before after for the last child element of this cell. + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link + * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} + */ + public int getBreakAfter() { + return breakAfter; + } + + /** + * Don't use, reserved for TableCellLM. TODO + * + * @param breakAfter the breakAfter to set + */ + public void setBreakAfter(int breakAfter) { + this.breakAfter = breakAfter; + } + } diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index 485c63ea2..d89f43370 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -335,6 +335,7 @@ class ActiveCell { } else { nextStep.set(afterNextStep); nextStep.start = previousStep.end + 1; + afterNextStep.start = nextStep.start; if (afterNextStep.end < elementList.size() - 1) { gotoNextLegalBreak(); } @@ -406,17 +407,6 @@ class ActiveCell { } /** - * Returns true if some content of this cell is part of the chosen next step. - * - * @return true if this cell's next step is inferior or equal to the next minimal step - */ - boolean contributesContent() { - // return includedInLastStep() && the cell hasn't finished yet, otherwise there's - // nothing more to contribute - return includedInLastStep() && nextStep.end >= nextStep.start; - } - - /** * Returns true if this cell would be finished after the given step. That is, it would * be included in the step and the end of its content would be reached. * @@ -469,14 +459,6 @@ class ActiveCell { } } - boolean isLastForcedBreak() { - return ((KnuthElement)elementList.get(nextStep.end)).isForcedBreak(); - } - - int getLastBreakClass() { - return ((KnuthPenalty)elementList.get(nextStep.end)).getBreakClass(); - } - boolean keepWithNextSignal() { return keepWithNextSignal; } diff --git a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java index 6d66da097..0127f4d81 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java @@ -40,6 +40,7 @@ import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.ListElement; import org.apache.fop.layoutmgr.MinOptMaxUtil; import org.apache.fop.traits.MinOptMax; +import org.apache.fop.util.BreakUtil; class RowGroupLayoutManager { @@ -66,11 +67,13 @@ class RowGroupLayoutManager { */ int getBreakBefore() { TableRow rowFO = rowGroup[0].getTableRow(); + int breakBefore; if (rowFO == null) { - return Constants.EN_AUTO; + breakBefore = Constants.EN_AUTO; } else { - return rowFO.getBreakBefore(); + breakBefore = rowFO.getBreakBefore(); } + return BreakUtil.compareBreakClasses(breakBefore, rowGroup[0].getBreakBefore()); } /** @@ -81,11 +84,14 @@ class RowGroupLayoutManager { */ int getBreakAfter() { TableRow rowFO = rowGroup[rowGroup.length - 1].getTableRow(); + int breakAfter; if (rowFO == null) { - return Constants.EN_AUTO; + breakAfter = Constants.EN_AUTO; } else { - return rowFO.getBreakAfter(); + breakAfter = rowFO.getBreakAfter(); } + return BreakUtil.compareBreakClasses(breakAfter, + rowGroup[rowGroup.length - 1].getBreakAfter()); } public LinkedList getNextKnuthElements(LayoutContext context, int alignment, int bodyType) { diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 26880faea..022ff0589 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -160,7 +160,17 @@ class RowPainter { for (int i = 0; i < colCount; i++) { GridUnit currentGU = currentRow.getGridUnit(i); if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0 - && (lastInPart || currentGU.isLastGridUnitRowSpan())) { + && (lastInPart || currentGU.isLastGridUnitRowSpan()) + && firstCellParts[i] != null) { + // TODO + // The last test above is a workaround for the stepping algorithm's + // fundamental flaw making it unable to produce the right element list for + // multiple breaks inside a same row group. + // (see http://wiki.apache.org/xmlgraphics-fop/TableLayout/KnownProblems) + // In some extremely rare cases (forced breaks, very small page height), a + // TableContentPosition produced during row delaying may end up alone on a + // page. It will not contain the CellPart instances for the cells starting + // the next row, so firstCellParts[i] will still be null for those ones. int cellHeight = cellHeights[i]; cellHeight += lastCellParts[i].getConditionalAfterContentLength(); cellHeight += lastCellParts[i].getBorderPaddingAfter(lastInPart); @@ -177,7 +187,8 @@ class RowPainter { for (int i = 0; i < colCount; i++) { GridUnit currentGU = currentRow.getGridUnit(i); if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0 - && (lastInPart || currentGU.isLastGridUnitRowSpan())) { + && (lastInPart || currentGU.isLastGridUnitRowSpan()) + && firstCellParts[i] != null) { assert firstCellParts[i].pgu == currentGU.getPrimary(); int borderBeforeWhich; if (firstCellParts[i].start == 0) { diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 9469a1121..fbc118723 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -210,7 +210,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager // with a SpaceResolver.SpaceHandlingBreakPosition element, having no // LM associated to it. Thus it will stop early instead of adding // areas for following Positions. The above test aims at preventing - // such a situation from occuring. add a null penalty to allow a break + // such a situation from occurring. add a null penalty to allow a break // between blocks contentList.add(new BreakElement( new Position(this), 0, context)); @@ -246,6 +246,16 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } //Space resolution SpaceResolver.resolveElementList(returnList); + if (((KnuthElement) returnList.getFirst()).isForcedBreak()) { + primaryGridUnit.setBreakBefore(((KnuthPenalty) returnList.getFirst()).getBreakClass()); + returnList.removeFirst(); + assert !returnList.isEmpty(); + } + if (((KnuthElement) returnList.getLast()).isForcedBreak()) { + KnuthPenalty p = (KnuthPenalty) returnList.getLast(); + primaryGridUnit.setBreakAfter(p.getBreakClass()); + p.setP(0); + } getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId()); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index baf1bd369..c09b9b076 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -48,6 +48,7 @@ import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.TraitSetter; import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition; +import org.apache.fop.util.BreakUtil; /** * Layout manager for table contents, particularly managing the creation of combined element lists. @@ -212,10 +213,14 @@ public class TableContentLayoutManager implements PercentBaseContext { while ((rowGroup = iter.getNextRowGroup()) != null) { RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper); - if (breakBetween == Constants.EN_AUTO) { - // TODO improve - breakBetween = rowGroupLM.getBreakBefore(); - } + // TODO + // The RowGroupLM.getBreakBefore method will work correctly only after + // getNextKnuthElements is called. Indeed TableCellLM will set the values for + // breaks on PrimaryGridUnit once it has got the Knuth elements of its + // children. This can be changed once all the LMs adopt the same scheme of + // querying childrens LMs for breaks instead of producing penalty elements + List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); + breakBetween = BreakUtil.compareBreakClasses(breakBetween, rowGroupLM.getBreakBefore()); if (breakBetween != Constants.EN_AUTO) { if (returnList.size() > 0) { BreakElement breakPoss = (BreakElement) returnList.getLast(); @@ -226,7 +231,7 @@ public class TableContentLayoutManager implements PercentBaseContext { 0, -KnuthPenalty.INFINITE, breakBetween, context)); } } - returnList.addAll(rowGroupLM.getNextKnuthElements(context, alignment, bodyType)); + returnList.addAll(nextRowGroupElems); breakBetween = rowGroupLM.getBreakAfter(); } // Break after the table's last row diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 4eff1e931..0b494bf2d 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -37,6 +37,7 @@ import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.Position; +import org.apache.fop.util.BreakUtil; /** * This class processes row groups to create combined element lists for tables. @@ -243,6 +244,12 @@ public class TableStepper { if (signalKeepWithNext || getTableLM().mustKeepTogether()) { p = KnuthPenalty.INFINITE; } + if (rowFinished && activeRowIndex < rowGroup.length - 1) { + nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, + rowGroup[activeRowIndex].getBreakAfter()); + nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, + rowGroup[activeRowIndex + 1].getBreakBefore()); + } if (nextBreakClass != Constants.EN_AUTO) { log.trace("Forced break encountered"); p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0) @@ -381,33 +388,8 @@ public class TableStepper { nextBreakClass = Constants.EN_AUTO; for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - nextBreakClass = compareBreakClasses(nextBreakClass, activeCell.signalNextStep(step)); - } - } - - // TODO replace that with a proper 1.5 enumeration ASAP - // TODO this has nothing to do here - private static int getBreakClassPriority(int breakClass) { - switch (breakClass) { - case Constants.EN_AUTO: return 0; - case Constants.EN_COLUMN: return 1; - case Constants.EN_PAGE: return 2; - case Constants.EN_EVEN_PAGE: return 3; - case Constants.EN_ODD_PAGE: return 3; - default: throw new IllegalArgumentException(); - } - } - - // TODO even-page and odd-page can't be compared to each other and instead create a - // conflict situation. For now the first encountered break will win, but eventually - // some warning message should be sent to the user. - private static int compareBreakClasses(int b1, int b2) { - int p1 = getBreakClassPriority(b1); - int p2 = getBreakClassPriority(b2); - if (p1 < p2) { - return b2; - } else { - return b1; + nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, + activeCell.signalNextStep(step)); } } diff --git a/src/java/org/apache/fop/util/BreakUtil.java b/src/java/org/apache/fop/util/BreakUtil.java new file mode 100644 index 000000000..c0528464d --- /dev/null +++ b/src/java/org/apache/fop/util/BreakUtil.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.util; + +import org.apache.fop.fo.Constants; + +/** + * A utility class for manipulating break classes (the break-before and break-after properties). + */ +public final class BreakUtil { + + private BreakUtil() { } + + // TODO replace that with a proper 1.5 enumeration ASAP + private static int getBreakClassPriority(int breakClass) { + switch (breakClass) { + case Constants.EN_AUTO: return 0; + case Constants.EN_COLUMN: return 1; + case Constants.EN_PAGE: return 2; + case Constants.EN_EVEN_PAGE: return 3; + case Constants.EN_ODD_PAGE: return 3; + default: throw new IllegalArgumentException(); + } + } + + /** + * Compares the given break classes and return the one that wins. even-page and + * odd-page win over page, which wins over column, which wins over auto. If even-page + * and odd-page are compared to each other, which one will be returned is undefined. + * + * @param break1 a break class, one of {@link Constants#EN_AUTO}, + * {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE}, + * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} + * @param break2 another break class + * @return the break class that wins the comparison + */ + public static int compareBreakClasses(int break1, int break2) { + // TODO implement some warning mechanism if even-page and odd-page are being compared + int p1 = getBreakClassPriority(break1); + int p2 = getBreakClassPriority(break2); + if (p1 < p2) { + return break2; + } else { + return break1; + } + } + +} |