From fb7baa3fc88f52b683e176de77f18839612a65b4 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Mon, 2 Jun 2014 20:19:36 +0000 Subject: [PATCH] FOP-1099: process footnotes coming from table headers or footers The footnote will appear once at the first (resp. last) occurrence of the table-header (resp. -footer). Patch by Matthias Reischenbacher, applied with modifications. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1599344 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/layoutmgr/FootenoteUtil.java | 75 ++++ .../layoutmgr/inline/LineLayoutManager.java | 13 +- .../layoutmgr/list/ListItemLayoutManager.java | 15 +- .../table/TableContentLayoutManager.java | 22 +- .../footnote_in_table-header.xml | 373 ++++++++++++++++++ 5 files changed, 470 insertions(+), 28 deletions(-) create mode 100644 src/java/org/apache/fop/layoutmgr/FootenoteUtil.java create mode 100644 test/layoutengine/standard-testcases/footnote_in_table-header.xml diff --git a/src/java/org/apache/fop/layoutmgr/FootenoteUtil.java b/src/java/org/apache/fop/layoutmgr/FootenoteUtil.java new file mode 100644 index 000000000..0b8b59f92 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/FootenoteUtil.java @@ -0,0 +1,75 @@ +/* + * 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.layoutmgr; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; + +import org.apache.fop.layoutmgr.inline.KnuthInlineBox; + +public final class FootenoteUtil { + + private FootenoteUtil() { + } + + /** + * Returns the footnotes contained in the given element list. + */ + public static List getFootnotes(List elemenList) { + return getFootnotes(elemenList, 0, elemenList.size() - 1); + } + + /** + * Returns the footnotes contained in the given element list. + * + * @param startIndex index in the element list from which to start the scan, inclusive + * @param endIndex index in the element list at which to stop the scan, inclusive + */ + public static List getFootnotes(List elemenList, int startIndex, int endIndex) { + ListIterator iter = elemenList.listIterator(startIndex); + List footnotes = null; + while (iter.nextIndex() <= endIndex) { + ListElement element = iter.next(); + if (element instanceof KnuthInlineBox && ((KnuthInlineBox) element).isAnchor()) { + footnotes = getFootnoteList(footnotes); + footnotes.add(((KnuthInlineBox) element).getFootnoteBodyLM()); + } else if (element instanceof KnuthBlockBox && ((KnuthBlockBox) element).hasAnchors()) { + footnotes = getFootnoteList(footnotes); + footnotes.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs()); + } + } + if (footnotes == null) { + return Collections.emptyList(); + } else { + return footnotes; + } + } + + private static List getFootnoteList(List footnotes) { + if (footnotes == null) { + return new ArrayList(); + } else { + return footnotes; + } + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java index 25d8c0872..28d49031f 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java @@ -50,6 +50,7 @@ import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.BreakingAlgorithm; import org.apache.fop.layoutmgr.ElementListObserver; +import org.apache.fop.layoutmgr.FootenoteUtil; import org.apache.fop.layoutmgr.InlineKnuthSequence; import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBlockBox; @@ -979,17 +980,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager endIndex = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos(); // create a list of the FootnoteBodyLM handling footnotes // whose citations are in this line - List footnoteList = new LinkedList(); - ListIterator elementIterator = seq.listIterator(startIndex); - while (elementIterator.nextIndex() <= endIndex) { - KnuthElement element = elementIterator.next(); - if (element instanceof KnuthInlineBox - && ((KnuthInlineBox) element).isAnchor()) { - footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM()); - } else if (element instanceof KnuthBlockBox) { - footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs()); - } - } + List footnoteList = FootenoteUtil.getFootnotes(seq, startIndex, endIndex); startIndex = endIndex + 1; LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i); if (baselineOffset < 0) { diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java index 773506632..053452f03 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java @@ -39,7 +39,7 @@ import org.apache.fop.layoutmgr.BreakOpportunity; import org.apache.fop.layoutmgr.BreakOpportunityHelper; import org.apache.fop.layoutmgr.ElementListObserver; import org.apache.fop.layoutmgr.ElementListUtils; -import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager; +import org.apache.fop.layoutmgr.FootenoteUtil; import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBox; @@ -322,18 +322,9 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage // collect footnote information // TODO this should really not be done like this. ListItemLM should remain as // footnote-agnostic as possible - LinkedList footnoteList = null; - ListElement el; + LinkedList footnoteList = new LinkedList(); for (int i = 0; i < elementLists.length; i++) { - for (int j = start[i]; j <= end[i]; j++) { - el = (ListElement) elementLists[i].get(j); - if (el instanceof KnuthBlockBox && ((KnuthBlockBox) el).hasAnchors()) { - if (footnoteList == null) { - footnoteList = new LinkedList(); - } - footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs()); - } - } + footnoteList.addAll(FootenoteUtil.getFootnotes(elementLists[i], start[i], end[i])); } // add the new elements diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 4f17c2d0c..d4b54939f 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -39,12 +39,15 @@ import org.apache.fop.fo.flow.table.TableBody; import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; +import org.apache.fop.layoutmgr.FootenoteUtil; import org.apache.fop.layoutmgr.Keep; +import org.apache.fop.layoutmgr.KnuthBlockBox; import org.apache.fop.layoutmgr.KnuthBox; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPossPosIter; import org.apache.fop.layoutmgr.LayoutContext; +import org.apache.fop.layoutmgr.LayoutManager; import org.apache.fop.layoutmgr.ListElement; import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.PositionIterator; @@ -147,6 +150,7 @@ public class TableContentLayoutManager implements PercentBaseContext { KnuthBox headerAsFirst = null; KnuthBox headerAsSecondToLast = null; KnuthBox footerAsLast = null; + LinkedList returnList = new LinkedList(); if (headerIter != null && headerList == null) { this.headerList = getKnuthElementsForRowIterator( headerIter, context, alignment, TableRowIterator.HEADER); @@ -158,12 +162,18 @@ public class TableContentLayoutManager implements PercentBaseContext { } TableHeaderFooterPosition pos = new TableHeaderFooterPosition( getTableLM(), true, this.headerList); - KnuthBox box = new KnuthBox(headerNetHeight, pos, false); + List footnoteList = FootenoteUtil.getFootnotes(headerList); + KnuthBox box = (footnoteList.isEmpty() || !getTableLM().getTable().omitHeaderAtBreak()) + ? new KnuthBox(headerNetHeight, pos, false) + : new KnuthBlockBox(headerNetHeight, footnoteList, pos, false); if (getTableLM().getTable().omitHeaderAtBreak()) { //We can simply add the table header at the start //of the whole list headerAsFirst = box; } else { + if (!footnoteList.isEmpty()) { + returnList.add(new KnuthBlockBox(0, footnoteList, new Position(getTableLM()), true)); + } headerAsSecondToLast = box; } } @@ -179,11 +189,13 @@ public class TableContentLayoutManager implements PercentBaseContext { //We can simply add the table footer at the end of the whole list TableHeaderFooterPosition pos = new TableHeaderFooterPosition( getTableLM(), false, this.footerList); - KnuthBox box = new KnuthBox(footerNetHeight, pos, false); - footerAsLast = box; + List footnoteList = FootenoteUtil.getFootnotes(footerList); + footerAsLast = footnoteList.isEmpty() + ? new KnuthBox(footerNetHeight, pos, false) + : new KnuthBlockBox(footerNetHeight, footnoteList, pos, false); } - LinkedList returnList = getKnuthElementsForRowIterator( - bodyIter, context, alignment, TableRowIterator.BODY); + returnList.addAll(getKnuthElementsForRowIterator( + bodyIter, context, alignment, TableRowIterator.BODY)); if (headerAsFirst != null) { int insertionPoint = 0; if (returnList.size() > 0 && ((ListElement)returnList.getFirst()).isForcedBreak()) { diff --git a/test/layoutengine/standard-testcases/footnote_in_table-header.xml b/test/layoutengine/standard-testcases/footnote_in_table-header.xml new file mode 100644 index 000000000..11ec1bd7d --- /dev/null +++ b/test/layoutengine/standard-testcases/footnote_in_table-header.xml @@ -0,0 +1,373 @@ + + + + + +

+ A footnote from a table-header should appear once at the bottom of the first page. +

+
+ + + + + + + + + + Before the table + + + + + + + Header 1.1 + * + + * Footnote from the table-header. + + + + + Header 1.2 + + + + + + + Footer 1.1 + + + Footer 1.2 + † + + † Footnote from the table-footer. + + + + + + + + + Cell 1.1 + + + Cell 1.2 + + + + + Cell 2.1 + + + Cell 2.2 + + + + + + + + + Before the table + + + + + + + Header 1.1 + * + + * Footnote from the table-header. + + + + + Header 1.2 + + + + + + + Footer 1.1 + + + Footer 1.2 + † + + † Footnote from the table-footer. + + + + + + + + + Cell 1.1 + + + Cell 1.2 + + + + + Cell 2.1 + + + Cell 2.2 + + + + + Cell 3.1 + + + Cell 3.2 + + + + + Cell 4.1 + + + Cell 4.2 + + + + + Cell 5.1 + + + Cell 5.2 + + + + + Cell 6.1 + + + Cell 6.2 + + + + + Cell 7.1 + + + Cell 7.2 + + + + + + + + + Before the table + + + + + + + Header 1.1 + * + + * Footnote from the table-header. + + + + + Header 1.2 + + + + + + + Footer 1.1 + + + Footer 1.2 + † + + † Footnote from the table-footer. + + + + + + + + + Cell 1.1 + + + Cell 1.2 + + + + + Cell 2.1 + + + Cell 2.2 + + + + + + + + + Before the table + + + + + + + Header 1.1 + * + + * Footnote from the table-header. + + + + + Header 1.2 + + + + + + + Footer 1.1 + + + Footer 1.2 + † + + † Footnote from the table-footer. + + + + + + + + + Cell 1.1 + + + Cell 1.2 + + + + + Cell 2.1 + + + Cell 2.2 + + + + + Cell 3.1 + + + Cell 3.2 + + + + + Cell 4.1 + + + Cell 4.2 + + + + + Cell 5.1 + + + Cell 5.2 + + + + + Cell 6.1 + + + Cell 6.2 + + + + + Cell 7.1 + + + Cell 7.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-- 2.39.5