--- /dev/null
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * Utilities for Knuth element lists.
+ */
+public class ElementListUtils {
+
+ /**
+ * Removes all legal breaks in an element list.
+ * @param elements the element list
+ */
+ public static void removeLegalBreaks(LinkedList elements) {
+ ListIterator i = elements.listIterator();
+ while (i.hasNext()) {
+ KnuthElement el = (KnuthElement)i.next();
+ if (el.isPenalty()) {
+ KnuthPenalty penalty = (KnuthPenalty)el;
+ //Convert all penalties no break inhibitors
+ if (penalty.getP() < KnuthPenalty.INFINITE) {
+ i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE,
+ penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
+ }
+ } else if (el.isGlue()) {
+ i.previous();
+ if (el.isBox()) {
+ i.next();
+ i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false,
+ /*new Position(getTableLM())*/null, false));
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes all legal breaks in an element list. A constraint can be specified to limit the
+ * range in which the breaks are removed. Legal breaks occuring before at least
+ * constraint.opt space is filled will be removed.
+ * @param elements the element list
+ * @param constraint min/opt/max value to restrict the range in which the breaks are removed.
+ * @return true if the opt constraint is bigger than the list contents
+ */
+ public static boolean removeLegalBreaks(LinkedList elements, MinOptMax constraint) {
+ int len = 0;
+ ListIterator i = elements.listIterator();
+ while (i.hasNext()) {
+ KnuthElement el = (KnuthElement)i.next();
+ if (el.isPenalty()) {
+ KnuthPenalty penalty = (KnuthPenalty)el;
+ //Convert all penalties no break inhibitors
+ if (penalty.getP() < KnuthPenalty.INFINITE) {
+ i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE,
+ penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
+ }
+ } else if (el.isGlue()) {
+ len += el.getW();
+ i.previous();
+ if (el.isBox()) {
+ i.next();
+ i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false,
+ /*new Position(getTableLM())*/null, false));
+ }
+ } else {
+ len += el.getW();
+ }
+ if (len > constraint.opt) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Calculates the content length of the given element list. Warning: It doesn't take any
+ * stretch and shrink possibilities into account.
+ * @param elems the element list
+ * @param start element at which to start
+ * @param end element at which to stop
+ * @return the content length
+ */
+ public static int calcContentLength(List elems, int start, int end) {
+ ListIterator iter = elems.listIterator(start);
+ int count = end - start + 1;
+ int len = 0;
+ while (iter.hasNext()) {
+ KnuthElement el = (KnuthElement)iter.next();
+ if (el.isBox()) {
+ len += el.getW();
+ } else if (el.isGlue()) {
+ len += el.getW();
+ } else {
+ //log.debug("Ignoring penalty: " + el);
+ //ignore penalties
+ }
+ count--;
+ if (count == 0) {
+ break;
+ }
+ }
+ return len;
+ }
+
+ /**
+ * Calculates the content length of the given element list. Warning: It doesn't take any
+ * stretch and shrink possibilities into account.
+ * @param elems the element list
+ * @return the content length
+ */
+ public static int calcContentLength(List elems) {
+ return calcContentLength(elems, 0, elems.size() - 1);
+ }
+
+}
private List gridUnits = new java.util.ArrayList();
private int index;
private int bodyType;
- private MinOptMax height = new MinOptMax(0);
+ private MinOptMax height;
+ private MinOptMax explicitHeight;
public EffRow(int index, int bodyType) {
this.index = index;
return this.height;
}
- public void setHeight(MinOptMax height) {
- this.height = height;
+ public void setHeight(MinOptMax mom) {
+ this.height = mom;
+ }
+
+ public MinOptMax getExplicitHeight() {
+ return this.explicitHeight;
+ }
+
+ public void setExplicitHeight(MinOptMax mom) {
+ this.explicitHeight = mom;
}
public List getGridUnits() {
sb.append(" in footer");
}
sb.append(", ").append(height);
+ sb.append(", ").append(explicitHeight);
sb.append(", ").append(gridUnits.size()).append(" gu");
sb.append("}");
return sb.toString();
import org.apache.fop.fo.flow.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
if (headerIter != null) {
this.headerList = getKnuthElementsForRowIterator(
headerIter, context, alignment, TableRowIterator.HEADER);
- removeLegalBreaks(this.headerList);
- this.headerNetHeight = calcCellHeightFromContents(this.headerList);
+ ElementListUtils.removeLegalBreaks(this.headerList);
+ this.headerNetHeight = ElementListUtils.calcContentLength(this.headerList);
if (log.isDebugEnabled()) {
log.debug("==> Header: " + headerNetHeight + " - " + this.headerList);
}
if (footerIter != null) {
this.footerList = getKnuthElementsForRowIterator(
footerIter, context, alignment, TableRowIterator.FOOTER);
- removeLegalBreaks(this.footerList);
- this.footerNetHeight = calcCellHeightFromContents(this.footerList);
+ ElementListUtils.removeLegalBreaks(this.footerList);
+ this.footerNetHeight = ElementListUtils.calcContentLength(this.footerList);
if (log.isDebugEnabled()) {
log.debug("==> Footer: " + footerNetHeight + " - " + this.footerList);
}
return returnList;
}
- private void removeLegalBreaks(LinkedList elements) {
- ListIterator i = elements.listIterator();
- while (i.hasNext()) {
- KnuthElement el = (KnuthElement)i.next();
- if (el.isPenalty()) {
- KnuthPenalty penalty = (KnuthPenalty)el;
- //Convert all penalties no break inhibitors
- if (penalty.getP() < KnuthPenalty.INFINITE) {
- i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE,
- penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
- }
- } else if (el.isGlue()) {
- i.previous();
- if (el.isBox()) {
- i.next();
- i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false,
- new Position(getTableLM()), false));
- }
- }
- }
- }
-
/**
* Creates Knuth elements by iterating over a TableRowIterator.
* @param iter TableRowIterator instance to fetch rows from
EffRow[] rowGroup) {
log.debug("Handling row group with " + rowGroup.length + " rows...");
MinOptMax[] rowHeights = new MinOptMax[rowGroup.length];
+ MinOptMax[] explicitRowHeights = new MinOptMax[rowGroup.length];
EffRow row;
int maxColumnCount = 0;
List pgus = new java.util.ArrayList(); //holds a list of a row's primary grid units
for (int rgi = 0; rgi < rowGroup.length; rgi++) {
row = rowGroup[rgi];
rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
+ explicitRowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
pgus.clear();
TableRow tableRow = null;
minContentHeight = Math.max(minContentHeight,
bpd.getMinimum().getLength().getValue());
}
+ MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd);
+
}
//Calculate width of cell
//Calculate height of cell contents
- primary.setContentLength(calcCellHeightFromContents(primary.getElements()));
+ primary.setContentLength(ElementListUtils.calcContentLength(
+ primary.getElements()));
maxCellHeight = Math.max(maxCellHeight, primary.getContentLength());
//Calculate height of row, see CSS21, 17.5.3 Table height algorithms
effCellContentHeight = Math.max(effCellContentHeight,
bpd.getMinimum().getLength().getValue());
}
+ if (gu.getRowSpanIndex() == 0) {
+ //TODO ATM only non-row-spanned cells are taken for this
+ MinOptMaxUtil.restrict(explicitRowHeights[rgi], bpd);
+ }
effCellContentHeight = Math.max(effCellContentHeight,
primary.getContentLength());
int borderWidths;
}
}
}
-
- log.debug("row: " + row);
-
- PrimaryGridUnit[] pguArray = new PrimaryGridUnit[pgus.size()];
- pguArray = (PrimaryGridUnit[])pgus.toArray(pguArray);
- /*
- LinkedList returnedList = getCombinedKnuthElementsForRow(pguArray, row,
- isHeaderFooter);
- if (returnedList != null) {
- returnList.addAll(returnedList);
- }*/
+ row.setExplicitHeight(explicitRowHeights[rgi]);
+ if (row.getHeight().opt > row.getExplicitHeight().max) {
+ log.warn("Contents of row " + row.getIndex() + " violate a maximum constraint "
+ + "in block-progression-dimension. Due to its contents the row grows "
+ + "to " + row.getHeight().opt + " millipoints. The row constraint resolve "
+ + "to " + row.getExplicitHeight());
+ }
}
if (log.isDebugEnabled()) {
log.debug("rowGroup:");
for (int i = 0; i < rowHeights.length; i++) {
- log.debug(" " + rowHeights[i]);
+ log.debug(" height=" + rowHeights[i] + " explicit=" + explicitRowHeights[i]);
}
}
TableStepper stepper = new TableStepper(this);
}
- private int calcCellHeightFromContents(List elems, int start, int end) {
- ListIterator iter = elems.listIterator(start);
- int count = end - start + 1;
- int len = 0;
- while (iter.hasNext()) {
- KnuthElement el = (KnuthElement)iter.next();
- if (el.isBox()) {
- len += el.getW();
- } else if (el.isGlue()) {
- len += el.getW();
- } else {
- //log.debug("Ignoring penalty: " + el);
- //ignore penalties
- }
- count--;
- if (count == 0) {
- break;
- }
- }
- return len;
- }
-
- private int calcCellHeightFromContents(List elems) {
- return calcCellHeightFromContents(elems, 0, elems.size() - 1);
- }
-
protected int getXOffsetOfGridUnit(GridUnit gu) {
int col = gu.getStartCol();
return startXOffset + getTableLM().getColumns().getXOffset(col + 1);
log.debug("getting len for " + i + " "
+ start[i] + "-" + end[i]);
readyCount++;
- int len = calcCellHeightFromContents(
+ int len = ElementListUtils.calcContentLength(
gridUnits[i].getElements(), start[i], end[i]);
+ if (start[i] == 0 && lastRow.getExplicitHeight().min > 0) {
+ len = Math.max(len, lastRow.getExplicitHeight().opt);
+ }
partLength[i] = len;
log.debug("len of part: " + len);
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
private void setupElementList(int column) {
GridUnit gu = getActiveGridUnit(column);
+ EffRow row = getActiveRow();
if (gu.isPrimary() && !gu.isEmpty()) {
PrimaryGridUnit pgu = (PrimaryGridUnit)gu;
- if (pgu.hasBPD()) {
- List list = new java.util.ArrayList(1);
- list.add(new KnuthBoxCellWithBPD(
- pgu.getEffectiveContentLength(), pgu));
- elementLists[column] = list;
+ if (row.getExplicitHeight().min > 0) {
+ boolean contentsSmaller = ElementListUtils.removeLegalBreaks(
+ pgu.getElements(), row.getExplicitHeight());
+ if (contentsSmaller) {
+ List list = new java.util.ArrayList(1);
+ list.add(new KnuthBoxCellWithBPD(
+ row.getExplicitHeight().opt, pgu));
+ elementLists[column] = list;
+ } else {
+ //Copy elements (LinkedList) to array lists to improve
+ //element access performance
+ elementLists[column] = new java.util.ArrayList(pgu.getElements());
+ }
} else {
//Copy elements (LinkedList) to array lists to improve
//element access performance