diff options
8 files changed, 412 insertions, 66 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 9794c7310..8abe1a3e8 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -179,12 +179,24 @@ public class TableContentLayoutManager implements PercentBaseContext { LinkedList returnList = getKnuthElementsForRowIterator( bodyIter, context, alignment, TableRowIterator.BODY); if (headerAsFirst != null) { - returnList.add(0, headerAsFirst); + int insertionPoint = 0; + if (returnList.size() > 0 && ((ListElement)returnList.getFirst()).isForcedBreak()) { + insertionPoint++; + } + returnList.add(insertionPoint, headerAsFirst); } else if (headerAsSecondToLast != null) { - returnList.add(headerAsSecondToLast); + int insertionPoint = returnList.size(); + if (returnList.size() > 0 && ((ListElement)returnList.getLast()).isForcedBreak()) { + insertionPoint--; + } + returnList.add(insertionPoint, headerAsSecondToLast); } if (footerAsLast != null) { - returnList.add(footerAsLast); + int insertionPoint = returnList.size(); + if (returnList.size() > 0 && ((ListElement)returnList.getLast()).isForcedBreak()) { + insertionPoint--; + } + returnList.add(insertionPoint, footerAsLast); } return returnList; } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 2d305d5fa..155111ac4 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -29,6 +29,7 @@ import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.ListElement; +import org.apache.fop.layoutmgr.NonLeafPosition; import org.apache.fop.layoutmgr.PositionIterator; import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.RelSide; @@ -248,7 +249,34 @@ public class TableLayoutManager extends BlockStackingLayoutManager log.debug("TableContentLM signals pending keep-with-previous"); context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); } - + + // Check if the table's content starts/ends with a forced break + // TODO this is hacky and will need to be handled better eventually + if (contentKnuthElements.size() > 0) { + ListElement element = (ListElement)contentKnuthElements.getFirst(); + if (element.isForcedBreak()) { + // The first row of the table(-body), or (the content of) one of its cells + // has a forced break-before + int breakBeforeTable = ((Table) fobj).getBreakBefore(); + if (breakBeforeTable == EN_PAGE + || breakBeforeTable == EN_COLUMN + || breakBeforeTable == EN_EVEN_PAGE + || breakBeforeTable == EN_ODD_PAGE) { + // There is already a forced break before the table; remove this one + // to prevent a double break + contentKnuthElements.removeFirst(); + } else { + element.setPosition(new NonLeafPosition(this, null)); + } + } + element = (ListElement)contentKnuthElements.getLast(); + if (element.isForcedBreak()) { + // The last row of the table(-body), or (the content of) one of its cells + // has a forced break-after + element.setPosition(new NonLeafPosition(this, null)); + } + } + //Set index values on elements coming from the content LM Iterator iter = contentKnuthElements.iterator(); while (iter.hasNext()) { @@ -256,67 +284,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager notifyPos(el.getPosition()); } log.debug(contentKnuthElements); - - if (contentKnuthElements.size() == 1 - && ((ListElement)contentKnuthElements.getFirst()).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 - //FIX ME - //bSpaceBeforeServed = false; - } - contentList.addAll(contentKnuthElements); - - // "wrap" the Position inside each element - // moving the elements from contentList to returnList - contentKnuthElements = new LinkedList(); - wrapPositionElements(contentList, returnList); - - return returnList; - } else { - /* - if (prevLM != null) { - // there is a block handled by prevLM - // before the one handled by curLM - if (mustKeepTogether() - || prevLM.mustKeepWithNext() - || curLM.mustKeepWithPrevious()) { - // add an infinite penalty to forbid a break between - // blocks - contentList.add(new KnuthPenalty(0, - KnuthElement.INFINITE, false, - new Position(this), false)); - } else if (!((KnuthElement) contentList.getLast()).isGlue()) { - // add a null penalty to allow a break between blocks - contentList.add(new KnuthPenalty(0, 0, false, - new Position(this), false)); - } else { - // the last element in contentList is a glue; - // it is a feasible breakpoint, there is no need to add - // a penalty - } - }*/ - contentList.addAll(contentKnuthElements); - if (contentKnuthElements.size() > 0) { - if (((ListElement)contentKnuthElements.getLast()).isForcedBreak()) { - // a descendant of this block has break-after - if (false /*curLM.isFinished()*/) { - // there is no other content in this block; - // it's useless to add space after before a page break - setFinished(true); - } - - contentKnuthElements = new LinkedList(); - wrapPositionElements(contentList, returnList); - - return returnList; - } - } - } + contentList.addAll(contentKnuthElements); wrapPositionElements(contentList, returnList); if (getTable().isSeparateBorderModel()) { addKnuthElementsForBorderPaddingAfter(returnList, true); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 2c676ae0b..60ccf2b0a 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -299,6 +299,7 @@ public class TableStepper { addedBoxLen += boxLen; boolean forcedBreak = false; + int breakClass = -1; //Put all involved grid units into a list List gridUnitParts = new java.util.ArrayList(maxColumnCount); for (int i = 0; i < columnCount; i++) { @@ -314,6 +315,7 @@ public class TableStepper { gridUnitParts.add(new GridUnitPart(pgu, start[i], end[i])); if (((KnuthElement)elementLists[i].get(end[i])).isForcedBreak()) { forcedBreak = true; + breakClass = ((KnuthPenalty)elementLists[i].get(end[i])).getBreakClass(); } } if (end[i] + 1 == elementLists[i].size()) { @@ -410,7 +412,7 @@ public class TableStepper { } p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0) } - returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, -1, context)); + returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context)); if (log.isDebugEnabled()) { log.debug("step=" + step + " (+" + increase + ")" diff --git a/test/layoutengine/standard-testcases/table-cell_break-after_last-block.xml b/test/layoutengine/standard-testcases/table-cell_break-after_last-block.xml new file mode 100644 index 000000000..d48321813 --- /dev/null +++ b/test/layoutengine/standard-testcases/table-cell_break-after_last-block.xml @@ -0,0 +1,66 @@ +<?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 break-after on the last block child of a cell in the last row of a table + without headers nor footers works properly. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="10cm" page-width="15cm" + margin-top="1cm" margin-bottom="0" margin-left="1cm" margin-right="1cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Before the table</fo:block> + <fo:table width="100%" table-layout="fixed" border-collapse="collapse" border="4pt solid black"> + <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.2 Line 1</fo:block> + <fo:block break-after="page">Cell 1.2 Line 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + <fo:block>After the table</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- Two pages --> + <eval expected="2" xpath="count(//pageViewport)"/> + <!-- Line "Before the table" + table on the first page --> + <eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block)"/> + <eval expected="Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea/text[1]"/> + <!-- Line "After the table" on the second page --> + <eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block)"/> + <eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[1]/lineArea/text[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/table-row_break-after_last-row-footer.xml b/test/layoutengine/standard-testcases/table-row_break-after_last-row-footer.xml new file mode 100644 index 000000000..41e7369df --- /dev/null +++ b/test/layoutengine/standard-testcases/table-row_break-after_last-row-footer.xml @@ -0,0 +1,74 @@ +<?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 break-after on the last row of a table with footers works properly. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="10cm" page-width="15cm" + margin-top="1cm" margin-bottom="0" margin-left="1cm" margin-right="1cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Before the table</fo:block> + <fo:table width="100%" table-layout="fixed" border-collapse="collapse" border="4pt solid black"> + <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/> + <fo:table-footer> + <fo:table-row> + <fo:table-cell border="2pt solid blue"> + <fo:block>Footer 1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid blue"> + <fo:block>Footer 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-footer> + <fo:table-body> + <fo:table-row break-after="page"> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + <fo:block>After the table</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- Two pages --> + <eval expected="2" xpath="count(//pageViewport)"/> + <!-- Line "Before the table" + table on the first page --> + <eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block)"/> + <eval expected="Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea/text[1]"/> + <!-- Line "After the table" on the second page --> + <eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block)"/> + <eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[1]/lineArea/text[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/table-row_break-after_last-row-header.xml b/test/layoutengine/standard-testcases/table-row_break-after_last-row-header.xml new file mode 100644 index 000000000..b23ec7292 --- /dev/null +++ b/test/layoutengine/standard-testcases/table-row_break-after_last-row-header.xml @@ -0,0 +1,74 @@ +<?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 break-after on the last row of a table with headers works properly. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="10cm" page-width="15cm" + margin-top="1cm" margin-bottom="0" margin-left="1cm" margin-right="1cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Before the table</fo:block> + <fo:table width="100%" table-layout="fixed" border-collapse="collapse" border="4pt solid black"> + <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/> + <fo:table-header> + <fo:table-row> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-header> + <fo:table-body> + <fo:table-row break-after="page"> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + <fo:block>After the table</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- Two pages --> + <eval expected="2" xpath="count(//pageViewport)"/> + <!-- Line "Before the table" + table on the first page --> + <eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block)"/> + <eval expected="Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea/text[1]"/> + <!-- Line "After the table" on the second page --> + <eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block)"/> + <eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[1]/lineArea/text[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/table-row_break-before_first-row-header.xml b/test/layoutengine/standard-testcases/table-row_break-before_first-row-header.xml new file mode 100644 index 000000000..f05f0096d --- /dev/null +++ b/test/layoutengine/standard-testcases/table-row_break-before_first-row-header.xml @@ -0,0 +1,74 @@ +<?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 break-before on the first row of a table with headers works properly. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="10cm" page-width="15cm" + margin-top="1cm" margin-bottom="0" margin-left="1cm" margin-right="1cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Before the table</fo:block> + <fo:table width="100%" table-layout="fixed" border-collapse="collapse" border="4pt solid black" table-omit-header-at-break="true"> + <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/> + <fo:table-header> + <fo:table-row> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-header> + <fo:table-body> + <fo:table-row break-before="page"> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + <fo:block>After the table</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- Two pages --> + <eval expected="2" xpath="count(//pageViewport)"/> + <!-- Only one line on the first page --> + <eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block)"/> + <eval expected="Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea/text[1]"/> + <!-- Table plus line "After the table" on the second page --> + <eval expected="2" xpath="count(//pageViewport[@nr=2]//flow/block)"/> + <eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[2]/lineArea/text[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/table_table-row_break-before.xml b/test/layoutengine/standard-testcases/table_table-row_break-before.xml new file mode 100644 index 000000000..e77ec4f65 --- /dev/null +++ b/test/layoutengine/standard-testcases/table_table-row_break-before.xml @@ -0,0 +1,76 @@ +<?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 there is only one page break when break-before is specified both on a + table and its first row. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="10cm" page-width="15cm" + margin-top="1cm" margin-bottom="0" margin-left="1cm" margin-right="1cm"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Before the table</fo:block> + <fo:table width="100%" table-layout="fixed" border-collapse="collapse" border="4pt solid black" + break-before="page"> + <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/> + <fo:table-header> + <fo:table-row> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid blue"> + <fo:block>Header 2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-header> + <fo:table-body> + <fo:table-row break-before="page"> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.1</fo:block> + </fo:table-cell> + <fo:table-cell border="2pt solid black"> + <fo:block>Cell 1.2</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + <fo:block>After the table</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- Two pages --> + <eval expected="2" xpath="count(//pageViewport)"/> + <!-- Only one line on the first page --> + <eval expected="1" xpath="count(//pageViewport[@nr=1]//flow/block)"/> + <eval expected="Before the table" xpath="//pageViewport[@nr=1]//flow/block[1]/lineArea/text[1]"/> + <!-- Table plus line "After the table" on the second page --> + <eval expected="2" xpath="count(//pageViewport[@nr=2]//flow/block)"/> + <eval expected="After the table" xpath="//pageViewport[@nr=2]//flow/block[2]/lineArea/text[1]"/> + </checks> +</testcase> |