You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2006/11/13 10:39:22 UTC
svn commit: r474218 [4/5] - in /xmlgraphics/fop/branches/Temp_Floats: ./
src/documentation/content/xdocs/trunk/ src/foschema/
src/java-1.4/org/apache/fop/image/ src/java/org/apache/fop/fo/
src/java/org/apache/fop/fo/expr/ src/java/org/apache/fop/fo/flo...
Added: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java?view=auto&rev=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java (added)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/FootnotesRecord.java Mon Nov 13 01:39:19 2006
@@ -0,0 +1,204 @@
+/*
+ * 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.breaking;
+
+import org.apache.fop.layoutmgr.PageBreakingAlgorithm;
+import org.apache.fop.layoutmgr.PageBreakingAlgorithm.KnuthPageNode;
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * A class that handles the placement of footnotes. Stores informations about
+ * existing footnotes, already placed ones, split footnotes, etc.
+ */
+public class FootnotesRecord extends OutOfLineRecord {
+
+ /**
+ * Progress informations for footnotes. When building pages, footnotes content will
+ * be put one unbreakable part at a time.
+ */
+ public class FootnotesProgress extends ProgressInfo {
+
+ /**
+ * Creates and initializes a new record.
+ */
+ public FootnotesProgress() {
+ super();
+ }
+
+ /**
+ * Creates a copy of the given record.
+ *
+ * @param footnotesProgress original progress information
+ */
+ public FootnotesProgress(FootnotesProgress footnotesProgress) {
+ super(footnotesProgress);
+ }
+
+ /**
+ * Checks whether there is some not yet typeset footnote content.
+ *
+ * @return <code>true</code> if the end of the footnote element list has not been
+ * reached yet
+ */
+ private boolean hasNext() {
+ return knuthSequences.size() > 0
+ && (lastInsertedIndex < knuthSequences.size() - 1 || !endOfOutOfLine());
+ }
+
+ /**
+ * Insert footnote content on the current page up to the next legal break. This
+ * may be within a footnote or at the end of one.
+ */
+ private void next() {
+ if (lastInsertedIndex < 0 || endOfOutOfLine()) {
+ // Go to the next footnote
+ lastInsertedIndex++;
+ lastElementOfLastInsertedIndex = -1;
+ nbSplit = 1;
+ } else { // We are still inside a footnote
+ nextInsideBreak();
+ }
+ }
+
+ /**
+ * If the last footnote of the previous page was split, places at least one more
+ * chunk of it on the current page. This would look very weird if the rest of a
+ * footnote split on one page would appear only two pages further. So this is
+ * necessary to put at least one chunk on the current page. If this leads to an
+ * unfeasible page, then the previous page will never appear in the optimal page
+ * layout anyway.
+ */
+ public void handleSplit() {
+ if (isLastSplit()) {
+ next();
+ addSeparator();
+ }
+ }
+
+ /**
+ * If the current page is a float-only page, handles the splitting of the last
+ * footnote of the previous page. Usually by adding at least a chunk of it on the
+ * current page, unless footnotes are not allowed on float-only pages (TODO this
+ * may lead to weird results (footnote continued only two pages further)).
+ *
+ * @param mode one of {@link PageBreakingAlgorithm#FLOAT_PAGE_MODE} or {@link
+ * PageBreakingAlgorithm#FLUSH_MODE}
+ * @param activeNodeRecorder
+ * @param normalContentProgress information about normal content already typeset
+ * @param beforeFloatsProgress information about before-floats already typeset
+ * @param previousNode node ending the previous page
+ */
+ public void handleSplit(int mode,
+ PageBreakingAlgorithm.ActiveNodeRecorder activeNodeRecorder,
+ PageBreakingAlgorithm.NormalContentProgressInfo normalContentProgress,
+ BeforeFloatsRecord.BeforeFloatsProgress beforeFloatsProgress,
+ KnuthPageNode previousNode) {
+ if (isLastSplit()) {
+ if (mode == PageBreakingAlgorithm.FLOAT_PAGE_MODE) {
+ if (PageBreakingAlgorithm.FOOTNOTES_ALLOWED_ON_FLOAT_PAGES) {
+ next();
+ addSeparator();
+ if (PageBreakingAlgorithm.FOOTNOTES_ONLY_PAGES_ALLOWED) {
+ activeNodeRecorder.handleNode(mode, normalContentProgress,
+ this, beforeFloatsProgress, previousNode);
+ }
+ }
+ } else { // mode == PageBreakingAlgorithm.FLUSH_MODE
+ next();
+ addSeparator();
+ activeNodeRecorder.handleNode(mode, normalContentProgress,
+ this, beforeFloatsProgress, previousNode);
+ }
+ }
+ }
+
+ /**
+ * Considers the placement of footnotes on the current page.
+ *
+ * @param mode one of {@link PageBreakingAlgorithm#NORMAL_MODE}, {@link
+ * PageBreakingAlgorithm#FLOAT_PAGE_MODE} or {@link
+ * PageBreakingAlgorithm#FLUSH_MODE}
+ * @param activeNodeRecorder
+ * @param normalContentProgress information about normal content already typeset
+ * @param beforeFloatsProgress information about before-floats already typeset
+ * @param previousNode node ending the previous page
+ */
+ public void consider(int mode,
+ PageBreakingAlgorithm.ActiveNodeRecorder activeNodeRecorder,
+ PageBreakingAlgorithm.NormalContentProgressInfo normalContentProgress,
+ BeforeFloatsRecord.BeforeFloatsProgress beforeFloatsProgress,
+ KnuthPageNode previousNode) {
+ beforeFloatsProgress.consider(mode, activeNodeRecorder,
+ normalContentProgress, this, previousNode);
+ if (alreadyInserted.getLength() == 0) {
+ addSeparator();
+ }
+ switch (mode) {
+ case PageBreakingAlgorithm.NORMAL_MODE:
+ while (hasNext()) {
+ next();
+ if (!activeNodeRecorder.handleNode(mode, normalContentProgress,
+ this, beforeFloatsProgress, previousNode)) {
+ break;
+ }
+ beforeFloatsProgress.consider(mode, activeNodeRecorder,
+ normalContentProgress, this, previousNode);
+ }
+ break;
+ case PageBreakingAlgorithm.FLOAT_PAGE_MODE:
+ if (PageBreakingAlgorithm.FOOTNOTES_ALLOWED_ON_FLOAT_PAGES) {
+ while (hasNext()) {
+ next();
+ if (PageBreakingAlgorithm.FOOTNOTES_ONLY_PAGES_ALLOWED) {
+ if (!activeNodeRecorder.handleNode(mode, normalContentProgress,
+ this, beforeFloatsProgress, previousNode)) {
+ break;
+ }
+ }
+ beforeFloatsProgress.consider(mode, activeNodeRecorder,
+ normalContentProgress, this, previousNode);
+ }
+ }
+ break;
+ case PageBreakingAlgorithm.FLUSH_MODE:
+ while (hasNext()) {
+ next();
+ if (!activeNodeRecorder.handleNode(mode, normalContentProgress,
+ this, beforeFloatsProgress, previousNode)) {
+ break;
+ }
+ beforeFloatsProgress.consider(mode, activeNodeRecorder,
+ normalContentProgress, this, previousNode);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Creates a new record for handling footnotes.
+ *
+ * @param footnoteSeparator dimensions of the separator between the normal content and
+ * the footnote area
+ */
+ public FootnotesRecord(MinOptMax footnoteSeparator) {
+ super(footnoteSeparator);
+ }
+}
Added: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakPosition.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakPosition.java?view=auto&rev=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakPosition.java (added)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakPosition.java Mon Nov 13 01:39:19 2006
@@ -0,0 +1,51 @@
+package org.apache.fop.layoutmgr.breaking;
+
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.LeafPosition;
+
+/**
+ * Private class to store information about inline breaks.
+ * Each value holds the start and end indexes into a List of
+ * inline break positions.
+ */
+public class LineBreakPosition extends LeafPosition {
+ /*
+ * TODO vh: fields temporarily made public to ease the moving of
+ * LineBreakPosition from a LineLayoutManager inner class to a top-level
+ * class.
+ */
+ public int iParIndex; // index of the Paragraph this Position refers to
+ public int iStartIndex; //index of the first element this Position refers to
+ public int availableShrink;
+ public int availableStretch;
+ public int difference;
+ public double dAdjust; // Percentage to adjust (stretch or shrink)
+ public double ipdAdjust; // Percentage to adjust (stretch or shrink)
+ public int startIndent;
+ public int lineHeight;
+ public int lineWidth;
+ public int spaceBefore;
+ public int spaceAfter;
+ public int baseline;
+
+ LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex,
+ int shrink, int stretch, int diff,
+ double ipdA, double adjust, int ind,
+ int lh, int lw, int sb, int sa, int bl) {
+ super(lm, iBreakIndex);
+ availableShrink = shrink;
+ availableStretch = stretch;
+ difference = diff;
+ iParIndex = index;
+ this.iStartIndex = iStartIndex;
+ ipdAdjust = ipdA;
+ dAdjust = adjust;
+ startIndent = ind;
+ lineHeight = lh;
+ lineWidth = lw;
+ spaceBefore = sb;
+ spaceAfter = sa;
+ baseline = bl;
+ }
+
+}
\ No newline at end of file
Added: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakingAlgorithm.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakingAlgorithm.java?view=auto&rev=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakingAlgorithm.java (added)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/LineBreakingAlgorithm.java Mon Nov 13 01:39:19 2006
@@ -0,0 +1,259 @@
+/*
+ * 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.breaking;
+
+import java.util.ListIterator;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.flow.Block;
+import org.apache.fop.layoutmgr.BreakingAlgorithm;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
+import org.apache.fop.layoutmgr.inline.AlignmentContext;
+import org.apache.fop.layoutmgr.inline.KnuthInlineBox;
+import org.apache.fop.layoutmgr.inline.LineLayoutManager;
+import org.apache.fop.layoutmgr.inline.LineLayoutManager.Paragraph;
+
+public class LineBreakingAlgorithm extends BreakingAlgorithm {
+ private LineLayoutManager thisLLM;
+ private int pageAlignment;
+ private int activePossibility;
+ private int addedPositions;
+ private int textIndent;
+ private int fillerMinWidth;
+ private int lineHeight;
+ private int lead;
+ private int follow;
+// private int maxDiff;
+ private static final double MAX_DEMERITS = 10e6;
+
+ public LineBreakingAlgorithm (int pageAlign,
+ int textAlign, int textAlignLast,
+ int indent, int fillerWidth,
+ int lh, int ld, int fl, boolean first,
+ int maxFlagCount, LineLayoutManager llm) {
+ super(textAlign, textAlignLast, first, false, maxFlagCount);
+ pageAlignment = pageAlign;
+ textIndent = indent;
+ fillerMinWidth = fillerWidth;
+ lineHeight = lh;
+ lead = ld;
+ follow = fl;
+ thisLLM = llm;
+ activePossibility = -1;
+// maxDiff = fobj.getWidows() >= fobj.getOrphans()
+// ? fobj.getWidows()
+// : fobj.getOrphans();
+ }
+
+ public void updateData1(int lineCount, double demerits) {
+ thisLLM.getLineLayouts().addPossibility(lineCount, demerits);
+ log.trace("Layout possibility in " + lineCount + " lines; break at position:");
+ }
+
+ public void updateData2(KnuthNode bestActiveNode,
+ KnuthSequence par,
+ int total) {
+ // compute indent and adjustment ratio, according to
+ // the value of text-align and text-align-last
+ int indent = 0;
+ int difference = bestActiveNode.difference;
+ int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
+ indent += (textAlign == Constants.EN_CENTER)
+ ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
+ indent += (bestActiveNode.line == 1 && bFirst && thisLLM.isFirstInBlock()) ? textIndent : 0;
+ double ratio = (textAlign == Constants.EN_JUSTIFY
+ || difference < 0 && -difference <= bestActiveNode.availableShrink)
+ ? bestActiveNode.adjustRatio : 0;
+
+ // add nodes at the beginning of the list, as they are found
+ // backwards, from the last one to the first one
+
+ // the first time this method is called, initialize activePossibility
+ if (activePossibility == -1) {
+ activePossibility = 0;
+ addedPositions = 0;
+ }
+
+ if (addedPositions == thisLLM.getLineLayouts().getLineCount(activePossibility)) {
+ activePossibility++;
+ addedPositions = 0;
+ }
+
+ if (difference + bestActiveNode.availableShrink < 0) {
+ if (log.isWarnEnabled()) {
+ log.warn(FONode.decorateWithContextInfo(
+ "Line " + (addedPositions + 1)
+ + " of a paragraph overflows the available area.", thisLLM.getFObj()));
+ }
+ }
+
+ //log.debug("LLM> (" + (thisLLM.getLineLayouts().getLineNumber(activePossibility) - addedPositions)
+ // + ") difference = " + difference + " ratio = " + ratio);
+ thisLLM.getLineLayouts().addBreakPosition(makeLineBreakPosition(par,
+ (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1 : 0),
+ bestActiveNode.position,
+ bestActiveNode.availableShrink - (addedPositions > 0
+ ? 0 : ((Paragraph)par).getLineFiller().opt - ((Paragraph)par).getLineFiller().min),
+ bestActiveNode.availableStretch,
+ difference, ratio, indent), activePossibility);
+ addedPositions++;
+ }
+
+ /* reset activePossibility, as if breakpoints have not yet been computed
+ */
+ public void resetAlgorithm() {
+ activePossibility = -1;
+ }
+
+ private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
+ int firstElementIndex,
+ int lastElementIndex,
+ int availableShrink,
+ int availableStretch,
+ int difference,
+ double ratio,
+ int indent) {
+ // line height calculation - spaceBefore may differ from spaceAfter
+ // by 1mpt due to rounding
+ int spaceBefore = (lineHeight - lead - follow) / 2;
+ int spaceAfter = lineHeight - lead - follow - spaceBefore;
+ // height before the main baseline
+ int lineLead = lead;
+ // maximum follow
+ int lineFollow = follow;
+ // true if this line contains only zero-height, auxiliary boxes
+ // and the actual line width is 0; in this case, the line "collapses"
+ // i.e. the line area will have bpd = 0
+ boolean bZeroHeightLine = (difference == thisLLM.getLineWidth());
+
+ // if line-stacking-strategy is "font-height", the line height
+ // is not affected by its content
+ if (((Block) thisLLM.getFObj()).getLineStackingStrategy() != Constants.EN_FONT_HEIGHT) {
+ ListIterator inlineIterator
+ = par.listIterator(firstElementIndex);
+ AlignmentContext lastAC = null;
+ int maxIgnoredHeight = 0; // See spec 7.13
+ for (int j = firstElementIndex;
+ j <= lastElementIndex;
+ j++) {
+ KnuthElement element = (KnuthElement) inlineIterator.next();
+ if (element instanceof KnuthInlineBox ) {
+ AlignmentContext ac = ((KnuthInlineBox) element).getAlignmentContext();
+ if (ac != null && lastAC != ac) {
+ if (!ac.usesInitialBaselineTable()
+ || ac.getAlignmentBaselineIdentifier() != Constants.EN_BEFORE_EDGE
+ && ac.getAlignmentBaselineIdentifier() != Constants.EN_AFTER_EDGE) {
+ int alignmentOffset = ac.getTotalAlignmentBaselineOffset();
+ if (alignmentOffset + ac.getAltitude() > lineLead) {
+ lineLead = alignmentOffset + ac.getAltitude();
+ }
+ if (ac.getDepth() - alignmentOffset > lineFollow) {
+ lineFollow = ac.getDepth() - alignmentOffset;
+ }
+ } else {
+ if (ac.getHeight() > maxIgnoredHeight) {
+ maxIgnoredHeight = ac.getHeight();
+ }
+ }
+ lastAC = ac;
+ }
+ if (bZeroHeightLine
+ && (!element.isAuxiliary() || ac != null && ac.getHeight() > 0)) {
+ bZeroHeightLine = false;
+ }
+ }
+ }
+
+ if (lineFollow < maxIgnoredHeight - lineLead) {
+ lineFollow = maxIgnoredHeight - lineLead;
+ }
+ }
+
+ thisLLM.setConstantLineHeight(lineLead + lineFollow);
+
+ if (bZeroHeightLine) {
+ return new LineBreakPosition(thisLLM,
+ thisLLM.getKnuthParagraphs().indexOf(par),
+ firstElementIndex, lastElementIndex,
+ availableShrink, availableStretch,
+ difference, ratio, 0, indent,
+ 0, thisLLM.getLineWidth(), 0, 0, 0);
+ } else {
+ return new LineBreakPosition(thisLLM,
+ thisLLM.getKnuthParagraphs().indexOf(par),
+ firstElementIndex, lastElementIndex,
+ availableShrink, availableStretch,
+ difference, ratio, 0, indent,
+ lineLead + lineFollow,
+ thisLLM.getLineWidth(), spaceBefore, spaceAfter,
+ lineLead);
+ }
+ }
+
+ public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
+ double threshold, boolean force,
+ int allowedBreaks) {
+ return super.findBreakingPoints(par, /*lineWidth,*/
+ threshold, force, allowedBreaks);
+ }
+
+ protected int filterActiveNodes() {
+ KnuthNode bestActiveNode = null;
+
+ if (pageAlignment == Constants.EN_JUSTIFY) {
+ // leave all active nodes and find the optimum line number
+ //log.debug("LBA.filterActiveNodes> " + activeNodeCount + " layouts");
+ for (int i = startLine; i < endLine; i++) {
+ for (KnuthNode node = getNode(i); node != null; node = node.next) {
+ //log.debug(" + lines = " + node.line + " demerits = " + node.totalDemerits);
+ bestActiveNode = compareNodes(bestActiveNode, node);
+ }
+ }
+
+ // scan the node set once again and remove some nodes
+ //log.debug("LBA.filterActiveList> layout selection");
+ for (int i = startLine; i < endLine; i++) {
+ for (KnuthNode node = getNode(i); node != null; node = node.next) {
+ //if (Math.abs(node.line - bestActiveNode.line) > maxDiff) {
+ //if (false) {
+ if (node.line != bestActiveNode.line
+ && node.totalDemerits > MAX_DEMERITS) {
+ //log.debug(" XXX lines = " + node.line + " demerits = " + node.totalDemerits);
+ deactivateNode(node);
+ } else {
+ //log.debug(" ok lines = " + node.line + " demerits = " + node.totalDemerits);
+ }
+ }
+ }
+ } else {
+ // leave only the active node with fewest total demerits
+ for (int i = startLine; i < endLine; i++) {
+ for (KnuthNode node = getNode(i); node != null; node = node.next) {
+ bestActiveNode = compareNodes(bestActiveNode, node);
+ if (node != bestActiveNode) {
+ deactivateNode(node);
+ }
+ }
+ }
+ }
+ return bestActiveNode.line;
+ }
+}
\ No newline at end of file
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/OutOfLineRecord.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/OutOfLineRecord.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/OutOfLineRecord.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/breaking/OutOfLineRecord.java Mon Nov 13 01:39:19 2006
@@ -20,295 +20,292 @@
package org.apache.fop.layoutmgr.breaking;
import java.util.ArrayList;
-import java.util.LinkedList;
+import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.PageBreakingAlgorithm;
import org.apache.fop.layoutmgr.SpaceResolver;
-import org.apache.fop.layoutmgr.PageBreakingAlgorithm.KnuthPageNode;
import org.apache.fop.traits.MinOptMax;
/**
* Helper class for dealing with out-of-line objects (before-floats and footnotes) when
* breaking text into pages. It stores the necessary informations to place out-of-line
* objects, and provides methods to manipulate them.
- *
+ *
* @see PageBreakingAlgorithm
*/
public class OutOfLineRecord {
-
+
/**
- * Stores informations about how many out-of-line objects have already been handled.
+ * During page breaking, records which out-of-line objects have already been handled,
+ * and how much of them are placed on the current page.
*/
- public static class ProgressInfo {
-
- /** Cumulated BPD length of all out-of-line objects inserted so far. */
- private int alreadyInsertedLength = 0;
+ class ProgressInfo {
/** Index of the last inserted out-of-line object. */
- private int lastInsertedIndex = -1;
+ int lastInsertedIndex;
/**
* Index of the last inserted Knuth element of the last inserted out-of-line
- * object. Currently only used for footnotes, as before-floats may not be split on
- * several pages. Might be useful when later dealing with floats that cannot even
- * be put on a page alone, however.
+ * object.
*/
- private int lastElementOfLastInsertedIndex = -1;
-
+ int lastElementOfLastInsertedIndex;
+
/**
- * Initializes this record, as if no out-of-line object were handled yet.
+ * Amount of out-of-lines put on the current page.
*/
- private void initialize() {
- alreadyInsertedLength = 0;
- lastInsertedIndex = -1;
- lastElementOfLastInsertedIndex = -1;
+ ElasticLength alreadyInserted = new ElasticLength();
+
+ /**
+ * Number of times the last out-of-line is split. The initial value is 1, and is
+ * reset each time the end of an out-of-line is reached. The purpose is to compute
+ * additional demerits for split out-of-lines.
+ */
+ int nbSplit;
+
+ /**
+ * Creates and initializes a new record.
+ *
+ * @see OutOfLineRecord#initialize()
+ */
+ ProgressInfo() {
+ initialize();
}
/**
- * @return a copy of this record
+ * Creates a copy of the given record.
+ *
+ * @param progressInfo original record
*/
- public ProgressInfo copy() {
- ProgressInfo info = new ProgressInfo();
- info.alreadyInsertedLength = alreadyInsertedLength;
- info.lastInsertedIndex = lastInsertedIndex;
- info.lastElementOfLastInsertedIndex = lastElementOfLastInsertedIndex;
- return info;
+ ProgressInfo(ProgressInfo progressInfo) {
+ this.lastInsertedIndex = progressInfo.lastInsertedIndex;
+ this.lastElementOfLastInsertedIndex = progressInfo.lastElementOfLastInsertedIndex;
+ this.alreadyInserted.set(progressInfo.alreadyInserted);
+ this.nbSplit = progressInfo.nbSplit;
}
/**
- * Returns the cumulated length of all already typeset out-of-line objects.
- * @return the total length in the block-progression-direction
+ * Returns the amount of out-of-lines inserted on the current page.
+ *
+ * @return the amount of out-of-lines inserted on the current page
*/
- public int getAlreadyInsertedLength() {
- return alreadyInsertedLength;
+ public ElasticLength getInserted() {
+ return alreadyInserted;
}
/**
- * Returns the index of the last element of the last already typeset out-of-line
- * object.
- * @return the index of the last placed KnuthElement
+ * Returns the number of times the last out-of-line is split.
+ *
+ * @return the number of times the last out-of-line is split
+ */
+ public int getNbSplit() {
+ return nbSplit;
+ }
+
+ /**
+ * Returns the index of the last element of the last inserted out-of-line.
+ *
+ * @return the index of the last element of the last inserted out-of-line
*/
public int getLastElementOfLastInsertedIndex() {
return lastElementOfLastInsertedIndex;
}
/**
- * @return the index of the last already typeset out-of-line object.
+ * Returns the index of the last inserted out-of-line.
+ *
+ * @return the index of the last inserted out-of-line
*/
public int getLastInsertedIndex() {
return lastInsertedIndex;
}
- public String toString() {
- return "length=" + alreadyInsertedLength
- + ", index=" + lastInsertedIndex
- + ", elt=" + lastElementOfLastInsertedIndex;
+ /**
+ * Initializes this record such that no out-of-line has been inserted yet.
+ */
+ public void initialize() {
+ lastInsertedIndex = -1;
+ lastElementOfLastInsertedIndex = -1;
+ alreadyInserted.reset();
+ nbSplit = 1;
}
- }
-
- /**
- * Sequences of KnuthElement corresponding to already encountered out-of-line objects.
- * This is a List of List of KnuthElement.
- */
- private List knuthSequences = null;
- /**
- * Each element of this list corresponds to the cumulated length in the BPD of all the
- * out-of-line objects up to the given index. This is a List of Integer.
- *
- * @see OutOfLineRecord#knuthSequences
- */
- private List cumulativeLengths = null;
+ /**
+ * Records progress status for out-of-lines up to the previous page.
+ *
+ * @param info progress informations for the previous page
+ */
+ public void setPrevious(ProgressInfo info) {
+ lastInsertedIndex = info.lastInsertedIndex;
+ lastElementOfLastInsertedIndex = info.lastElementOfLastInsertedIndex;
+ if (lastInsertedIndex >= 0) {
+ List lastOutOfLine = ((List) knuthSequences.get(lastInsertedIndex));
+ // If the last out-of-line was split, go just before the first next box
+ while (lastElementOfLastInsertedIndex < lastOutOfLine.size() - 2
+ && !((KnuthElement) lastOutOfLine.get(lastElementOfLastInsertedIndex + 1)).isBox()) {
+ lastElementOfLastInsertedIndex++;
+ }
+ if (lastElementOfLastInsertedIndex < lastOutOfLine.size() - 1) {
+ // We haven't reached the end of the out-of-line yet
+ nbSplit = info.nbSplit + 1;
+ } else {
+ nbSplit = 1;
+ }
+ }
+ alreadyInserted.reset();
+ }
- /**
- * True if new out-of-line objects are cited in the sequence of Knuth elements since
- * the last encountered legal breakpoint.
- *
- * @see OutOfLineRecord#newSinceLastBreakpoint()
- */
- private boolean newSinceLastBreakpoint = false;
+ /**
+ * Checks whether there are still out-of-line objects to be placed.
+ *
+ * @return <code>true</code> if not all out-of-lines have been placed yet,
+ * otherwise <code>false</code>
+ */
+ public boolean remaining() {
+ return (lastInsertedIndex < knuthSequences.size() - 1) || isLastSplit();
+ }
- /**
- * Index of the first newly encountered out-of-line object since the last legal
- * breakpoint.
- *
- * @see OutOfLineRecord#knuthSequences
- */
- private int firstNewIndex = 0;
+ /**
+ * Returns the number of still to-be-placed out-of-lines.
+ * @return the number of not yet typeset out-of-line objects.
+ */
+ public int getNbOfDeferred() {
+ return knuthSequences.size() - 1 - lastInsertedIndex;
+ }
- /**
- * Dimension in the BPD of the separator between the out-of-line area and the main
- * area.
- */
- private MinOptMax separatorLength = null;
+ /**
+ * Checks whether the end of the current out-of-line has been reached.
+ *
+ * @return <code>true</code> if the whole out-of-line has been placed, otherwise
+ * <code>false</code>
+ */
+ boolean endOfOutOfLine() {
+ return lastElementOfLastInsertedIndex
+ >= ((List) knuthSequences.get(lastInsertedIndex)).size() - 1;
+ }
- /**
- * Record of already handled out-of-line objects.
- *
- * @see ProgressInfo
- */
- private ProgressInfo progressInfo;
+ /**
+ * Checks whether the last out-of-line placed on the current page must be split or
+ * not.
+ *
+ * @return <code>true</code> if the last typeset out-of-line object must be split on
+ * several pages.
+ */
+ public boolean isLastSplit() {
+ return lastInsertedIndex >= 0 && !endOfOutOfLine();
+ }
- public OutOfLineRecord(MinOptMax separatorLength) {
- this.separatorLength = separatorLength;
- this.progressInfo = new ProgressInfo();
- }
+ /**
+ * Adds the dimensions of the separator between the out-of-line area and the main
+ * content to the amount of out-of-lines already placed on the current page.
+ */
+ public void addSeparator() {
+ alreadyInserted.add(separator);
+ }
- /**
- * Initializes this record, as if no out-of-line object were handled yet.
- */
- public void initialize() {
- knuthSequences = null;
- cumulativeLengths = null;
- newSinceLastBreakpoint = false;
- firstNewIndex = 0;
- progressInfo.initialize();
- }
+ /**
+ * Places on the current page out-of-line content up to the next legal break in the current
+ * out-of-line. This method is meant to be called by subclasses of this class, not
+ * by external classes even in the same package.
+ * <p><strong>Pre-condition:</strong> it is supposed that we are <em>inside</em>
+ * the out-of-line, and that we haven't reached its end yet.
+ */
+ void nextInsideBreak() {
+ List knuthSequence = (List) knuthSequences.get(lastInsertedIndex);
+ Iterator elementIter = knuthSequence.listIterator(lastElementOfLastInsertedIndex + 1);
+ boolean prevIsBox = false;
+ do {
+ lastElementOfLastInsertedIndex++;
+ KnuthElement element = (KnuthElement) elementIter.next();
+ if (element.isBox()) {
+ alreadyInserted.add(0, element.getW(), 0);
+ prevIsBox = true;
+ } else if (element.isGlue()) {
+ if (prevIsBox) {
+ break;
+ }
+ alreadyInserted.add(element.getZ(), element.getW(), element.getY());
+ prevIsBox = false;
+ } else {
+ if (element.getP() < KnuthElement.INFINITE) {
+ alreadyInserted.add(0, element.getW(), 0);
+ break;
+ }
+ prevIsBox = false;
+ }
+ } while (lastElementOfLastInsertedIndex < knuthSequence.size() - 1);
+ if (lastElementOfLastInsertedIndex == knuthSequence.size() - 1) {
+ nbSplit = 0;
+ }
+ }
- /**
- * @return the informations about already handled out-of-line objects
- */
- public ProgressInfo getProgress() {
- return this.progressInfo;
+ public String toString() {
+ return "index=" + lastInsertedIndex
+ + ", elt=" + lastElementOfLastInsertedIndex
+ + ", inserted=" + alreadyInserted
+ + ", splits=" + nbSplit;
+ }
}
/**
- * @return the length in the BPD of the separator between the out-of-line area and the
- * main area.
+ * Sequences of KnuthElement corresponding to already encountered out-of-line objects.
+ * This is a List of List of KnuthElement.
*/
- public MinOptMax getSeparatorLength() {
- return separatorLength;
- }
+ List knuthSequences = new ArrayList();
/**
- * @return the total length of already encountered out-of-line objects
+ * Dimension in the BPD of the separator between the out-of-line area and the main
+ * area.
*/
- public int getTotalLength() {
- if (cumulativeLengths == null || cumulativeLengths.size() == 0) {
- return 0;
- } else {
- return ((Integer) cumulativeLengths.get(cumulativeLengths.size() - 1)).intValue();
- }
- }
+ private ElasticLength separator = null;
/**
- * @return true if out-of-line objects have already been encountered (but not
- * necessarily typeset yet)
+ * Creates a new record for a given type of out-of-lines.
+ *
+ * @param separator dimensions of the separator between the out-of-line area and the
+ * main area
*/
- public boolean existing() {
- return (knuthSequences != null && knuthSequences.size() > 0);
- }
-
- public void resetNewSinceLastBreakpoint() {
- newSinceLastBreakpoint = false;
+ public OutOfLineRecord(MinOptMax separator) {
+ this.separator = new ElasticLength(separator.opt - separator.min,
+ separator.opt,
+ separator.max - separator.opt);
}
/**
- * @return true if new out-of-line objects are cited in the sequence of Knuth
- * elements since the last encountered legal breakpoint.
+ * Initializes this record, as if no out-of-line object were handled yet.
*/
- public boolean newSinceLastBreakpoint() {
- return newSinceLastBreakpoint;
+ public void initialize() {
+ knuthSequences = new ArrayList();
}
/**
* Records one or more newly encountered out-of-line objects.
- * @param elementLists the list of corresponding Knuth sequences
+ *
+ * @param elementLists the list of corresponding Knuth sequences. This is a
+ * List<List<KnuthElement>>.
*/
public void add(List elementLists) {
- // Initialize stuff if necessary
- if (knuthSequences == null) {
- knuthSequences = new ArrayList();
- cumulativeLengths = new ArrayList();
- }
- if (!newSinceLastBreakpoint) {
- newSinceLastBreakpoint = true;
- firstNewIndex = knuthSequences.size();
- }
- // compute the total length of the footnotes
ListIterator elementListsIterator = elementLists.listIterator();
while (elementListsIterator.hasNext()) {
- LinkedList noteList = (LinkedList) elementListsIterator.next();
-
- //Space resolution (Note: this does not respect possible stacking constraints
- //between footnotes!)
- SpaceResolver.resolveElementList(noteList);
-
- int noteLength = 0;
- knuthSequences.add(noteList);
- ListIterator noteListIterator = noteList.listIterator();
- while (noteListIterator.hasNext()) {
- KnuthElement element = (KnuthElement) noteListIterator.next();
- if (element.isBox() || element.isGlue()) {
- noteLength += element.getW();
- }
- }
- cumulativeLengths.add(new Integer(getTotalLength() + noteLength));
- }
- }
-
- /**
- * Sets the progress informations to the given values. Called whenever a new active
- * node is considered; the informations regarding already handled out-of-line objects
- * must be set to the active node's values in order to know from where to start the
- * placement of further objects.
- *
- * @param info progress informations of the currently considered active node
- */
- public void setProgress(ProgressInfo info) {
- this.progressInfo.alreadyInsertedLength = info.alreadyInsertedLength;
- this.progressInfo.lastElementOfLastInsertedIndex = info.lastElementOfLastInsertedIndex;
- this.progressInfo.lastInsertedIndex = info.lastInsertedIndex;
- }
+ List knuthSequence = (List) elementListsIterator.next();
- /* Unless I'm wrong, newOnThisPagePlusPiecesFromPrevious always implies
- * notAllInserted. And if A => B, then A && B <=> B
- * So this code may be simplified, see deferred() below
- */
- /**
-// * Returns true if their are (pieces of) footnotes to be typeset on the
-// * current page.
-// * @param listIndex index of the last inserted footnote for the
-// * currently considered active node
-// * @param elementIndex index of the last element of the last inserted footnote
-// * @param length total length of all footnotes inserted so far
-// */
-// public boolean deferredFootnotes(ProgressInfo progressInfo) {
-// boolean newOnThisPagePlusPiecesFromPrevious =
-// newSinceLastBreakpoint()
-// && firstNewIndex != 0
-// && (progressInfo.lastInsertedIndex < firstNewIndex - 1
-// || progressInfo.lastElementOfLastInsertedIndex <
-// ((LinkedList) knuthSequences.get(progressInfo.lastInsertedIndex)).size() - 1);
-// boolean notAllInserted = progressInfo.alreadyInsertedLength < getTotalLength();
-// return notAllInserted;
-// }
+ // Space resolution (Note: this does not respect possible stacking constraints
+ // /between/ out-of-lines!)
+ SpaceResolver.resolveElementList(knuthSequence);
- /**
- * @return <code>true</code> if some out-of-line objects have not already been
- * typeset.
- */
- public boolean deferred() {
- return progressInfo.alreadyInsertedLength < getTotalLength();
- }
-
- /**
- * @return the number of not yet typeset out-of-line objects.
- */
- public int getNbOfDeferred() {
- return knuthSequences.size() - 1 - progressInfo.lastInsertedIndex;
+ knuthSequences.add(knuthSequence);
+ }
}
/**
- * @return <code>true</code> if the last typeset out-of-line object must be split on
- * several pages.
+ * Returns <code>true</code> if out-of-lines have already been encountered.
+ *
+ * @return <code>true</code> if out-of-lines are recorded, possibly not yet typeset
*/
- public boolean isSplit() {
- return (progressInfo.lastElementOfLastInsertedIndex
- < ((LinkedList) knuthSequences.get(progressInfo.lastInsertedIndex)).size() - 1);
+ public boolean existing() {
+ return knuthSequences.size() > 0;
}
/**
@@ -318,284 +315,19 @@
* it does not exist
*/
public List getSequence(int index) {
- /*TODO vh: bof */
- if (knuthSequences == null) {
- return null;
- } else {
- return (List) knuthSequences.get(index);
- }
- }
-
- /**
- * Tries to split the flow of footnotes to put one part on the current page.
- * @param prevNodeProgress informations about footnotes already inserted on the
- * previous page
- * @param availableLength available space for footnotes on this page
- * @param canDeferOldFootnotes
- * @return the length of footnotes which could be inserted on this page
- */
- public int getFootnoteSplit(ProgressInfo prevNodeProgress,
- int availableLength, boolean canDeferOldFootnotes) {
- if (availableLength <= 0) {
- progressInfo.alreadyInsertedLength = prevNodeProgress.getAlreadyInsertedLength();
- return 0;
- } else {
- // the split should contain a piece of the last footnote
- // together with all previous, not yet inserted footnotes;
- // but if this is not possible, try adding as much content as possible
- int splitLength = 0;
- ListIterator noteListIterator = null;
- KnuthElement element = null;
- boolean somethingAdded = false;
-
- // prevNodeProgress.lastInsertedIndex and
- // prevNodeProgress.lastElementOfLastInsertedIndex points to the last footnote element
- // already placed in a page: advance to the next element
- int listIndex = prevNodeProgress.lastInsertedIndex;
- int elementIndex = prevNodeProgress.lastElementOfLastInsertedIndex;
- if (listIndex == -1
- || elementIndex == ((LinkedList) knuthSequences.get(listIndex)).size() - 1) {
- listIndex++;
- elementIndex = 0;
- } else {
- elementIndex++;
- }
-
- // try adding whole notes
- // if there are more than 1 footnote to insert
- if (knuthSequences.size() - 1 > listIndex) {
- // add the previous footnotes: these cannot be broken or deferred
- if (!canDeferOldFootnotes
- && newSinceLastBreakpoint()
- && firstNewIndex > 0) {
- splitLength = ((Integer) cumulativeLengths.get(firstNewIndex - 1)).intValue()
- - prevNodeProgress.alreadyInsertedLength;
- listIndex = firstNewIndex;
- elementIndex = 0;
- }
- // try adding the new footnotes
- while (((Integer) cumulativeLengths.get(listIndex)).intValue()
- - prevNodeProgress.alreadyInsertedLength <= availableLength) {
- splitLength = ((Integer) cumulativeLengths.get(listIndex)).intValue()
- - prevNodeProgress.alreadyInsertedLength;
- somethingAdded = true;
- listIndex++;
- elementIndex = 0;
- }
- // as this method is called only if it is not possible to insert
- // all footnotes, at this point listIndex and elementIndex points to
- // an existing element, the next one we will try to insert
- }
-
- // try adding a split of the next note
- noteListIterator = ((List) knuthSequences.get(listIndex)).listIterator(elementIndex);
-
- int prevSplitLength = 0;
- int prevIndex = -1;
- int index = -1;
-
- while (!somethingAdded || splitLength <= availableLength) {
- if (!somethingAdded) {
- somethingAdded = true;
- } else {
- prevSplitLength = splitLength;
- prevIndex = index;
- }
- // get a sub-sequence from the note element list
- boolean bPrevIsBox = false;
- while (noteListIterator.hasNext()) {
- // as this method is called only if it is not possible to insert
- // all footnotes, and we have already tried (and failed) to insert
- // this whole footnote, the while loop will never reach the end
- // of the note sequence
- element = (KnuthElement) noteListIterator.next();
- if (element.isBox()) {
- // element is a box
- splitLength += element.getW();
- bPrevIsBox = true;
- } else if (element.isGlue()) {
- // element is a glue
- if (bPrevIsBox) {
- // end of the sub-sequence
- index = noteListIterator.previousIndex();
- break;
- }
- bPrevIsBox = false;
- splitLength += element.getW();
- } else {
- // element is a penalty
- if (element.getP() < KnuthElement.INFINITE) {
- // end of the sub-sequence
- index = noteListIterator.previousIndex();
- break;
- }
- }
- }
- }
- // if prevSplitLength is 0, this means that the available length isn't enough
- // to insert even the smallest split of the last footnote, so we cannot end a
- // page here
- // if prevSplitLength is > 0 we can insert some footnote content in this page
- // and insert the remaining in the following one
- if (!somethingAdded) {
- // there was not enough space to add a piece of the first new footnote
- // this is not a good break
- prevSplitLength = 0;
- } else if (prevSplitLength > 0) {
- // prevIndex is -1 if we have added only some whole footnotes
- progressInfo.lastInsertedIndex = (prevIndex != -1) ? listIndex : listIndex - 1;
- progressInfo.lastElementOfLastInsertedIndex = (prevIndex != -1)
- ? prevIndex
- : ((LinkedList) knuthSequences.get(progressInfo.lastInsertedIndex)).size() - 1;
- }
- progressInfo.alreadyInsertedLength
- = prevNodeProgress.getAlreadyInsertedLength() + prevSplitLength;
- return prevSplitLength;
- }
+ return (List) knuthSequences.get(index);
}
- /**
- * Tries to split the flow of floats to put some floats on the current page.
- * @param prevProgress floats already inserted on the previous page
- * @param availableLength available space for floats
- * @return the length of floats which could be placed on the current page
- */
- public int getFloatSplit(ProgressInfo prevProgress, int availableLength) {
- /*
- * Normally this method is called only when there is some place for
- * floats => availableLength > 0
- */
- int splitLength = 0;
- int listIndex = prevProgress.lastInsertedIndex + 1;
-
- while (listIndex < knuthSequences.size()
- && ((Integer) cumulativeLengths.get(listIndex)).intValue()
- - prevProgress.alreadyInsertedLength <= availableLength) {
- splitLength = ((Integer) cumulativeLengths.get(listIndex)).intValue()
- - prevProgress.alreadyInsertedLength;
- listIndex++;
- }
- progressInfo.lastInsertedIndex = listIndex - 1;
- progressInfo.alreadyInsertedLength = prevProgress.alreadyInsertedLength + splitLength;
- return splitLength;
- }
-
- /**
- * Places on the current page all of the out-of-line objects not yet inserted.
- */
- public void insertAll() {
- progressInfo.alreadyInsertedLength = getTotalLength();
- progressInfo.lastInsertedIndex = knuthSequences.size() - 1;
- progressInfo.lastElementOfLastInsertedIndex
- = ((List) knuthSequences.get(progressInfo.lastInsertedIndex)).size() - 1;
- }
/**
* When restarting the algorithm from a given point, reset the informations about
* out-of-line objects to the values at that point.
* @param elementLists out-of-line sequences which are met after the restarting point,
- * and thus must be removed from the list of already encoutered objects.
+ * and thus must be removed from the list of already encountered objects.
*/
public void reset(List elementLists) {
for (int i = 0; i < elementLists.size(); i++) {
knuthSequences.remove(knuthSequences.size() - 1);
- cumulativeLengths.remove(cumulativeLengths.size() - 1);
- }
- }
-
- /**
- * When the whole normal flow has been typeset and there are still footnotes to be
- * placed, creates as many pages as necessary to place them.
- */
- public void createFootnotePages(KnuthPageNode lastNode, PageBreakingAlgorithm algo, int lineWidth) {
- progressInfo.alreadyInsertedLength = lastNode.footnotesProgress.getAlreadyInsertedLength();
- progressInfo.lastInsertedIndex = lastNode.footnotesProgress.getLastInsertedIndex();
- progressInfo.lastElementOfLastInsertedIndex = lastNode.footnotesProgress.getLastElementOfLastInsertedIndex();
- int availableBPD = lineWidth;
- int split = 0;
- KnuthPageNode prevNode = lastNode;
-
- // create pages containing the remaining footnote bodies
- while (progressInfo.alreadyInsertedLength < getTotalLength()) {
- // try adding some more content
- if (((Integer) cumulativeLengths.get(progressInfo.lastInsertedIndex)).intValue() - progressInfo.alreadyInsertedLength
- <= availableBPD) {
- // add a whole footnote
- availableBPD -= ((Integer) cumulativeLengths.get(progressInfo.lastInsertedIndex)).intValue()
- - progressInfo.alreadyInsertedLength;
- progressInfo.alreadyInsertedLength = ((Integer)cumulativeLengths.get(progressInfo.lastInsertedIndex)).intValue();
- progressInfo.lastElementOfLastInsertedIndex
- = ((LinkedList)knuthSequences.get(progressInfo.lastInsertedIndex)).size() - 1;
- } else if ((split = getFootnoteSplit(progressInfo, availableBPD, true))
- > 0) {
- // add a piece of a footnote
- availableBPD -= split;
- // footnoteListIndex has already been set in getFootnoteSplit()
- // footnoteElementIndex has already been set in getFootnoteSplit()
- } else {
- // cannot add any content: create a new node and start again
- KnuthPageNode node = (KnuthPageNode)
- algo.createNode(lastNode.position, prevNode.line + 1, 1,
- progressInfo.alreadyInsertedLength - prevNode.footnotesProgress.getAlreadyInsertedLength(),
- 0, 0,
- 0, 0, 0,
- 0, 0, prevNode);
- algo.addNode(node.line, node);
- algo.removeNode(prevNode.line, prevNode);
-
- prevNode = node;
- availableBPD = lineWidth;
- }
- }
- // create the last node
- KnuthPageNode node = (KnuthPageNode)
- algo.createNode(lastNode.position, prevNode.line + 1, 1,
- getTotalLength() - prevNode.footnotesProgress.getAlreadyInsertedLength(), 0, 0,
- 0, 0, 0,
- 0, 0, prevNode);
- algo.addNode(node.line, node);
- algo.removeNode(prevNode.line, prevNode);
- }
-
- /* TODO vh: won't work when there are also footnotes. To be merged with createFootnotePages */
- public void createFloatPages(KnuthPageNode lastNode, PageBreakingAlgorithm algo, int lineWidth) {
- progressInfo.alreadyInsertedLength = lastNode.floatsProgress.getAlreadyInsertedLength();
- progressInfo.lastInsertedIndex = lastNode.floatsProgress.getLastInsertedIndex();
- int availableBPD = lineWidth;
- KnuthPageNode prevNode = lastNode;
-
- // create pages containing the remaining float bodies
- while (progressInfo.alreadyInsertedLength < getTotalLength()) {
- // try adding some more content
- if (((Integer) cumulativeLengths.get(progressInfo.lastInsertedIndex + 1)).intValue() - progressInfo.alreadyInsertedLength
- <= availableBPD) {
- // add a whole float
- progressInfo.lastInsertedIndex++;
- availableBPD -= ((Integer) cumulativeLengths.get(progressInfo.lastInsertedIndex)).intValue()
- - progressInfo.alreadyInsertedLength;
- progressInfo.alreadyInsertedLength = ((Integer)cumulativeLengths.get(progressInfo.lastInsertedIndex)).intValue();
- } else {
- // cannot add any content: create a new node and start again
- KnuthPageNode node = (KnuthPageNode)
- algo.createNode(lastNode.position, prevNode.line + 1, 1,
- progressInfo.alreadyInsertedLength - prevNode.floatsProgress.getAlreadyInsertedLength(),
- 0, 0,
- 0, 0, 0,
- 0, prevNode.totalDemerits + (progressInfo.lastInsertedIndex - prevNode.floatsProgress.lastInsertedIndex) * 10000, prevNode);
- algo.addNode(node.line, node);
- algo.removeNode(prevNode.line, prevNode);
-
- prevNode = node;
- availableBPD = lineWidth;
- }
}
- // create the last node
- KnuthPageNode node = (KnuthPageNode)
- algo.createNode(lastNode.position, prevNode.line + 1, 1,
- getTotalLength() - prevNode.floatsProgress.getAlreadyInsertedLength(), 0, 0,
- 0, 0, 0,
- 0, prevNode.totalDemerits + (progressInfo.lastInsertedIndex - prevNode.floatsProgress.lastInsertedIndex) * 10000, prevNode);
- algo.addNode(node.line, node);
- algo.removeNode(prevNode.line, prevNode);
}
}
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java Mon Nov 13 01:39:19 2006
@@ -47,6 +47,8 @@
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.layoutmgr.breaking.LineBreakPosition;
+import org.apache.fop.layoutmgr.breaking.LineBreakingAlgorithm;
import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.inline.InlineArea;
@@ -100,49 +102,6 @@
}
}
- /**
- * Private class to store information about inline breaks.
- * Each value holds the start and end indexes into a List of
- * inline break positions.
- */
- private static class LineBreakPosition extends LeafPosition {
- private int iParIndex; // index of the Paragraph this Position refers to
- private int iStartIndex; //index of the first element this Position refers to
- private int availableShrink;
- private int availableStretch;
- private int difference;
- private double dAdjust; // Percentage to adjust (stretch or shrink)
- private double ipdAdjust; // Percentage to adjust (stretch or shrink)
- private int startIndent;
- private int lineHeight;
- private int lineWidth;
- private int spaceBefore;
- private int spaceAfter;
- private int baseline;
-
- LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex,
- int shrink, int stretch, int diff,
- double ipdA, double adjust, int ind,
- int lh, int lw, int sb, int sa, int bl) {
- super(lm, iBreakIndex);
- availableShrink = shrink;
- availableStretch = stretch;
- difference = diff;
- iParIndex = index;
- this.iStartIndex = iStartIndex;
- ipdAdjust = ipdA;
- dAdjust = adjust;
- startIndent = ind;
- lineHeight = lh;
- lineWidth = lw;
- spaceBefore = sb;
- spaceAfter = sa;
- baseline = bl;
- }
-
- }
-
-
private int textAlignment = EN_JUSTIFY;
private int textAlignmentLast;
private int effectiveAlignment;
@@ -195,7 +154,7 @@
}
// this class represents a paragraph
- private class Paragraph extends InlineKnuthSequence {
+ public class Paragraph extends InlineKnuthSequence {
/** Number of elements to ignore at the beginning of the list. */
private int ignoreAtStart = 0;
/** Number of elements to ignore at the end of the list. */
@@ -221,6 +180,10 @@
lastLineEndIndent = endIndent;
}
+ public MinOptMax getLineFiller() {
+ return lineFiller;
+ }
+
public void startParagraph(int lw) {
lineWidth = lw;
startSequence();
@@ -307,233 +270,6 @@
}
}
- private class LineBreakingAlgorithm extends BreakingAlgorithm {
- private LineLayoutManager thisLLM;
- private int pageAlignment;
- private int activePossibility;
- private int addedPositions;
- private int textIndent;
- private int fillerMinWidth;
- private int lineHeight;
- private int lead;
- private int follow;
- private int maxDiff;
- private static final double MAX_DEMERITS = 10e6;
-
- public LineBreakingAlgorithm (int pageAlign,
- int textAlign, int textAlignLast,
- int indent, int fillerWidth,
- int lh, int ld, int fl, boolean first,
- int maxFlagCount, LineLayoutManager llm) {
- super(textAlign, textAlignLast, first, false, maxFlagCount);
- pageAlignment = pageAlign;
- textIndent = indent;
- fillerMinWidth = fillerWidth;
- lineHeight = lh;
- lead = ld;
- follow = fl;
- thisLLM = llm;
- activePossibility = -1;
- maxDiff = fobj.getWidows() >= fobj.getOrphans()
- ? fobj.getWidows()
- : fobj.getOrphans();
- }
-
- public void updateData1(int lineCount, double demerits) {
- lineLayouts.addPossibility(lineCount, demerits);
- log.trace("Layout possibility in " + lineCount + " lines; break at position:");
- }
-
- public void updateData2(KnuthNode bestActiveNode,
- KnuthSequence par,
- int total) {
- // compute indent and adjustment ratio, according to
- // the value of text-align and text-align-last
- int indent = 0;
- int difference = bestActiveNode.difference;
- int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
- indent += (textAlign == Constants.EN_CENTER)
- ? difference / 2 : (textAlign == Constants.EN_END) ? difference : 0;
- indent += (bestActiveNode.line == 1 && bFirst && isFirstInBlock) ? textIndent : 0;
- double ratio = (textAlign == Constants.EN_JUSTIFY
- || difference < 0 && -difference <= bestActiveNode.availableShrink)
- ? bestActiveNode.adjustRatio : 0;
-
- // add nodes at the beginning of the list, as they are found
- // backwards, from the last one to the first one
-
- // the first time this method is called, initialize activePossibility
- if (activePossibility == -1) {
- activePossibility = 0;
- addedPositions = 0;
- }
-
- if (addedPositions == lineLayouts.getLineCount(activePossibility)) {
- activePossibility++;
- addedPositions = 0;
- }
-
- if (difference + bestActiveNode.availableShrink < 0) {
- if (log.isWarnEnabled()) {
- log.warn(FONode.decorateWithContextInfo(
- "Line " + (addedPositions + 1)
- + " of a paragraph overflows the available area.", getFObj()));
- }
- }
-
- //log.debug("LLM> (" + (lineLayouts.getLineNumber(activePossibility) - addedPositions)
- // + ") difference = " + difference + " ratio = " + ratio);
- lineLayouts.addBreakPosition(makeLineBreakPosition(par,
- (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1 : 0),
- bestActiveNode.position,
- bestActiveNode.availableShrink - (addedPositions > 0
- ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min),
- bestActiveNode.availableStretch,
- difference, ratio, indent), activePossibility);
- addedPositions++;
- }
-
- /* reset activePossibility, as if breakpoints have not yet been computed
- */
- public void resetAlgorithm() {
- activePossibility = -1;
- }
-
- private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
- int firstElementIndex,
- int lastElementIndex,
- int availableShrink,
- int availableStretch,
- int difference,
- double ratio,
- int indent) {
- // line height calculation - spaceBefore may differ from spaceAfter
- // by 1mpt due to rounding
- int spaceBefore = (lineHeight - lead - follow) / 2;
- int spaceAfter = lineHeight - lead - follow - spaceBefore;
- // height before the main baseline
- int lineLead = lead;
- // maximum follow
- int lineFollow = follow;
- // true if this line contains only zero-height, auxiliary boxes
- // and the actual line width is 0; in this case, the line "collapses"
- // i.e. the line area will have bpd = 0
- boolean bZeroHeightLine = (difference == iLineWidth);
-
- // if line-stacking-strategy is "font-height", the line height
- // is not affected by its content
- if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) {
- ListIterator inlineIterator
- = par.listIterator(firstElementIndex);
- AlignmentContext lastAC = null;
- int maxIgnoredHeight = 0; // See spec 7.13
- for (int j = firstElementIndex;
- j <= lastElementIndex;
- j++) {
- KnuthElement element = (KnuthElement) inlineIterator.next();
- if (element instanceof KnuthInlineBox ) {
- AlignmentContext ac = ((KnuthInlineBox) element).getAlignmentContext();
- if (ac != null && lastAC != ac) {
- if (!ac.usesInitialBaselineTable()
- || ac.getAlignmentBaselineIdentifier() != EN_BEFORE_EDGE
- && ac.getAlignmentBaselineIdentifier() != EN_AFTER_EDGE) {
- int alignmentOffset = ac.getTotalAlignmentBaselineOffset();
- if (alignmentOffset + ac.getAltitude() > lineLead) {
- lineLead = alignmentOffset + ac.getAltitude();
- }
- if (ac.getDepth() - alignmentOffset > lineFollow) {
- lineFollow = ac.getDepth() - alignmentOffset;
- }
- } else {
- if (ac.getHeight() > maxIgnoredHeight) {
- maxIgnoredHeight = ac.getHeight();
- }
- }
- lastAC = ac;
- }
- if (bZeroHeightLine
- && (!element.isAuxiliary() || ac != null && ac.getHeight() > 0)) {
- bZeroHeightLine = false;
- }
- }
- }
-
- if (lineFollow < maxIgnoredHeight - lineLead) {
- lineFollow = maxIgnoredHeight - lineLead;
- }
- }
-
- constantLineHeight = lineLead + lineFollow;
-
- if (bZeroHeightLine) {
- return new LineBreakPosition(thisLLM,
- knuthParagraphs.indexOf(par),
- firstElementIndex, lastElementIndex,
- availableShrink, availableStretch,
- difference, ratio, 0, indent,
- 0, iLineWidth, 0, 0, 0);
- } else {
- return new LineBreakPosition(thisLLM,
- knuthParagraphs.indexOf(par),
- firstElementIndex, lastElementIndex,
- availableShrink, availableStretch,
- difference, ratio, 0, indent,
- lineLead + lineFollow,
- iLineWidth, spaceBefore, spaceAfter,
- lineLead);
- }
- }
-
- public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
- double threshold, boolean force,
- int allowedBreaks) {
- return super.findBreakingPoints(par, /*lineWidth,*/
- threshold, force, allowedBreaks);
- }
-
- protected int filterActiveNodes() {
- KnuthNode bestActiveNode = null;
-
- if (pageAlignment == EN_JUSTIFY) {
- // leave all active nodes and find the optimum line number
- //log.debug("LBA.filterActiveNodes> " + activeNodeCount + " layouts");
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- //log.debug(" + lines = " + node.line + " demerits = " + node.totalDemerits);
- bestActiveNode = compareNodes(bestActiveNode, node);
- }
- }
-
- // scan the node set once again and remove some nodes
- //log.debug("LBA.filterActiveList> layout selection");
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- //if (Math.abs(node.line - bestActiveNode.line) > maxDiff) {
- //if (false) {
- if (node.line != bestActiveNode.line
- && node.totalDemerits > MAX_DEMERITS) {
- //log.debug(" XXX lines = " + node.line + " demerits = " + node.totalDemerits);
- removeNode(i, node);
- } else {
- //log.debug(" ok lines = " + node.line + " demerits = " + node.totalDemerits);
- }
- }
- }
- } else {
- // leave only the active node with fewest total demerits
- for (int i = startLine; i < endLine; i++) {
- for (KnuthNode node = getNode(i); node != null; node = node.next) {
- bestActiveNode = compareNodes(bestActiveNode, node);
- if (node != bestActiveNode) {
- removeNode(i, node);
- }
- }
- }
- }
- return bestActiveNode.line;
- }
- }
-
private int constantLineHeight = 12000;
@@ -556,6 +292,26 @@
lineHeight = lh;
lead = l;
follow = f;
+ }
+
+ public LineLayoutPossibilities getLineLayouts() {
+ return lineLayouts;
+ }
+
+ public boolean isFirstInBlock() {
+ return isFirstInBlock;
+ }
+
+ public int getLineWidth() {
+ return iLineWidth;
+ }
+
+ public void setConstantLineHeight(int constantLineHeight) {
+ this.constantLineHeight = constantLineHeight;
+ }
+
+ public List getKnuthParagraphs() {
+ return knuthParagraphs;
}
/** @see org.apache.fop.layoutmgr.LayoutManager */
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java Mon Nov 13 01:39:19 2006
@@ -30,6 +30,7 @@
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
@@ -145,6 +146,8 @@
if (firstLM == null) {
firstLM = lastLM;
}
+ } else if (pos instanceof SpaceHandlingBreakPosition) {
+ positionList.add(pos);
} else {
// pos was created by this ListBlockLM, so it must be ignored
}
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java Mon Nov 13 01:39:19 2006
@@ -288,7 +288,21 @@
int penaltyHeight = step
+ getMaxRemainingHeight(fullHeights, partialHeights)
- totalHeight;
+
+ //Additional penalty height from penalties in the source lists
+ int additionalPenaltyHeight = 0;
+ KnuthElement endEl = (KnuthElement)elementLists[0].get(end[0]);
+ if (endEl instanceof KnuthPenalty) {
+ additionalPenaltyHeight = ((KnuthPenalty)endEl).getW();
+ }
+ endEl = (KnuthElement)elementLists[1].get(end[1]);
+ if (endEl instanceof KnuthPenalty) {
+ additionalPenaltyHeight = Math.max(
+ additionalPenaltyHeight, ((KnuthPenalty)endEl).getW());
+ }
+
int boxHeight = step - addedBoxHeight - penaltyHeight;
+ penaltyHeight += additionalPenaltyHeight; //Add AFTER calculating boxHeight!
// add the new elements
addedBoxHeight += boxHeight;
@@ -300,7 +314,6 @@
if (keepWithNextActive || mustKeepTogether()) {
p = KnuthPenalty.INFINITE;
}
- //returnList.add(new KnuthPenalty(penaltyHeight, p, false, stepPosition, false));
returnList.add(new BreakElement(stepPosition, penaltyHeight, p, -1, context));
}
}
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java Mon Nov 13 01:39:19 2006
@@ -77,6 +77,8 @@
private int startXOffset;
private int usedBPD;
+ private TableStepper stepper = new TableStepper(this);
+
/**
* Main constructor
* @param parent Parent layout manager
@@ -144,15 +146,18 @@
this.headerList = getKnuthElementsForRowIterator(
headerIter, context, alignment, TableRowIterator.HEADER);
ElementListUtils.removeLegalBreaks(this.headerList);
- this.headerNetHeight = ElementListUtils.calcContentLength(this.headerList);
+ this.headerNetHeight =
+ ElementListUtils.calcContentLength(this.headerList);
if (log.isDebugEnabled()) {
- log.debug("==> Header: " + headerNetHeight + " - " + this.headerList);
+ log.debug("==> Header: "
+ + headerNetHeight + " - " + this.headerList);
}
TableHeaderFooterPosition pos = new TableHeaderFooterPosition(
getTableLM(), true, this.headerList);
KnuthBox box = new KnuthBox(headerNetHeight, pos, false);
if (getTableLM().getTable().omitHeaderAtBreak()) {
- //We can simply add the table header at the beginning of the whole list
+ //We can simply add the table header at the start
+ //of the whole list
headerAsFirst = box;
} else {
headerAsSecondToLast = box;
@@ -162,17 +167,17 @@
this.footerList = getKnuthElementsForRowIterator(
footerIter, context, alignment, TableRowIterator.FOOTER);
ElementListUtils.removeLegalBreaks(this.footerList);
- this.footerNetHeight = ElementListUtils.calcContentLength(this.footerList);
+ this.footerNetHeight =
+ ElementListUtils.calcContentLength(this.footerList);
if (log.isDebugEnabled()) {
- log.debug("==> Footer: " + footerNetHeight + " - " + this.footerList);
- }
- if (true /*getTableLM().getTable().omitFooterAtBreak()*/) {
- //We can simply add the table header at the end of the whole list
- TableHeaderFooterPosition pos = new TableHeaderFooterPosition(
- getTableLM(), false, this.footerList);
- KnuthBox box = new KnuthBox(footerNetHeight, pos, false);
- footerAsLast = box;
+ log.debug("==> Footer: "
+ + footerNetHeight + " - " + this.footerList);
}
+ //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;
}
LinkedList returnList = getKnuthElementsForRowIterator(
trIter, context, alignment, TableRowIterator.BODY);
@@ -192,7 +197,8 @@
* @param iter TableRowIterator instance to fetch rows from
* @param context Active LayoutContext
* @param alignment alignment indicator
- * @param bodyType Indicates what kind of body is being processed (BODY, HEADER or FOOTER)
+ * @param bodyType Indicates what kind of body is being processed
+ * (BODY, HEADER or FOOTER)
* @return An element list
*/
private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter,
@@ -211,7 +217,7 @@
pen.setP(-KnuthPenalty.INFINITE);
pen.setBreakClass(rowFO.getBreakBefore());
} else if (last instanceof BreakElement) {
- BreakElement breakPoss = (BreakElement)last;
+ BreakElement breakPoss = (BreakElement) last;
breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE);
breakPoss.setBreakClass(rowFO.getBreakBefore());
}
@@ -573,9 +579,7 @@
log.debug(" height=" + rowHeights[i] + " explicit=" + explicitRowHeights[i]);
}
}
- //TODO It may make sense to reuse the stepper since it allocates quite some space
- TableStepper stepper = new TableStepper(this);
- LinkedList returnedList = stepper.getCombinedKnuthElementsForRowGroup(
+ LinkedList returnedList = this.stepper.getCombinedKnuthElementsForRowGroup(
context, rowGroup, maxColumnCount, bodyType);
if (returnedList != null) {
returnList.addAll(returnedList);
Modified: xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableStepper.java?view=diff&rev=474218&r1=474217&r2=474218
==============================================================================
--- xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableStepper.java (original)
+++ xmlgraphics/fop/branches/Temp_Floats/src/java/org/apache/fop/layoutmgr/table/TableStepper.java Mon Nov 13 01:39:19 2006
@@ -72,10 +72,10 @@
*/
public TableStepper(TableContentLayoutManager tclm) {
this.tclm = tclm;
- this.activeRow = 0;
}
private void setup(int columnCount) {
+ this.activeRow = 0;
elementLists = new List[columnCount];
startRow = new int[columnCount];
start = new int[columnCount];
---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org