package org.apache.fop.layoutmgr;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public BestFitPosition(LayoutManager lm) {
super(lm);
}
+
public BestFitPosition(LayoutManager lm, List<ListElement> knuthList) {
super(lm);
this.knuthList = knuthList;
}
+
public List<Position> getPositionList() {
List<Position> positions = new LinkedList<Position>();
if (knuthList != null) {
List<ListElement> knuthList = new LinkedList<ListElement>();
- Iterator<List<ListElement>> iter = childrenLists.iterator();
- while (iter.hasNext()) {
-
- List<ListElement> childList = iter.next();
+ BestFitPenalty bestFitPenalty = new BestFitPenalty(new BestFitPosition(lm));
+ for (List<ListElement> childList : childrenLists) {
SpaceResolver.resolveElementList(childList);
int contentLength = ElementListUtils.calcContentLength(childList);
- BestFitPenalty bestFitPenalty =
- new BestFitPenalty(contentLength, childList,
- new BestFitPosition(lm));
- knuthList.add(bestFitPenalty);
+ bestFitPenalty.addVariant(childList, contentLength);
}
+ // TODO Adding the two enclosing boxes is definitely a dirty hack.
+ // Let's leave it like that for now, until I find a proper fix.
+ knuthList.add(new KnuthBox(0, new Position(lm), false));
+ knuthList.add(bestFitPenalty);
knuthList.add(new KnuthBox(0, new Position(lm), false));
return knuthList;
}
package org.apache.fop.layoutmgr;
+import java.util.ArrayList;
import java.util.List;
import org.apache.fop.layoutmgr.BestFitLayoutUtils.BestFitPosition;
/**
- * A penalty class used to specify a set of alternatives for the layout engine
+ * A type of penalty used to specify a set of alternatives for the layout engine
* to choose from. The chosen alternative must have an occupied size
- * that is less than the available BPD of the current page
- * and it must also be the best match when it is evaluated by {@link FittingStrategy}.
+ * that is less than the available BPD of the current page.
*/
public class BestFitPenalty extends KnuthPenalty {
- private final List<ListElement> knuthList;
- public boolean ignorePenalty;
+ public class Variant {
- public BestFitPenalty(int width, List<ListElement> knuthList, Position pos) {
- super(width, 0, false, pos, false);
- this.knuthList = knuthList;
+ public final List<ListElement> knuthList;
+ public final int width;
+
+ public Variant(List<ListElement> knuthList, int width) {
+ this.knuthList = knuthList;
+ this.width = width;
+ }
+ public KnuthElement toPenalty() {
+ return new KnuthPenalty(width, 0, false, null, false);
+ }
}
- public void activateContent() {
- BestFitPosition pos = getBestFitPosition();
- pos.setKnuthList(knuthList);
+ private final BestFitPosition bestFitPosition;
+
+ private final List<Variant> variantList;
+
+ public BestFitPenalty(BestFitPosition pos) {
+ super(0, 0, false, pos, false);
+ this.bestFitPosition = pos;
+ variantList = new ArrayList<Variant>();
}
- public int getWidth() {
- if (ignorePenalty) {
- return 0;
- }
- return super.getWidth();
+ public void addVariant(List<ListElement> knuthList, int width) {
+ variantList.add(new Variant(knuthList, width));
}
- public BestFitPosition getBestFitPosition() {
- Position pos = super.getPosition();
- while (pos != null) {
- if (pos instanceof BestFitPosition) {
- return (BestFitPosition) pos;
- }
- pos = pos.getPosition();
- }
- return null;
+ public void activatePenalty(Variant bestVariant) {
+ bestFitPosition.setKnuthList(bestVariant.knuthList);
+ }
+
+ public List<Variant> getVariantList() {
+ return variantList;
}
@Override
public String toString() {
String str = super.toString();
StringBuffer buffer = new StringBuffer(64);
-// buffer.append(" number of alternatives = " + alternatives.size());
-// buffer.append(" fitting-strategy = " + strategy.getStrategyName());
+ buffer.append(" number of variants = " + variantList.size());
return str + buffer.toString();
}
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
+import org.apache.fop.layoutmgr.BestFitPenalty.Variant;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.util.ListUtil;
private int currentKeepContext = Constants.EN_AUTO;
private KnuthNode lastBeforeKeepContextSwitch;
+ /** Holds the variant that should be assigned to the next node to be created */
+ private Variant variant;
+
/**
* Construct a page breaking algorithm.
* @param topLevelLM the top level layout manager
/** Index of the last inserted element of the last inserted footnote. */
public int footnoteElementIndex;
+ public final Variant variant;
+
public KnuthPageNode(int position,
int line, int fitness,
int totalWidth, int totalStretch, int totalShrink,
int totalFootnotes, int footnoteListIndex, int footnoteElementIndex,
double adjustRatio, int availableShrink, int availableStretch,
- int difference, double totalDemerits, KnuthNode previous) {
+ int difference, double totalDemerits, KnuthNode previous, Variant variant) {
super(position, line, fitness,
totalWidth, totalStretch, totalShrink,
adjustRatio, availableShrink, availableStretch,
this.totalFootnotes = totalFootnotes;
this.footnoteListIndex = footnoteListIndex;
this.footnoteElementIndex = footnoteElementIndex;
+ this.variant = variant;
}
}
private final int[] bestFootnotesLength = new int[4];
private final int[] bestFootnoteListIndex = new int[4];
private final int[] bestFootnoteElementIndex = new int[4];
+ private final Variant[] bestVariant = new Variant[4];
@Override
public void addRecord(double demerits, KnuthNode node, double adjust,
bestFootnotesLength[fitness] = insertedFootnotesLength;
bestFootnoteListIndex[fitness] = footnoteListIndex;
bestFootnoteElementIndex[fitness] = footnoteElementIndex;
+ bestVariant[fitness] = variant;
}
public int getFootnotesLength(int fitness) {
public int getFootnoteElementIndex(int fitness) {
return bestFootnoteElementIndex[fitness];
}
+
+ public Variant getVariant(int fitness) {
+ return bestVariant[fitness];
+ }
}
/** {@inheritDoc} */
totalWidth, totalStretch, totalShrink,
insertedFootnotesLength, footnoteListIndex, footnoteElementIndex,
adjustRatio, availableShrink, availableStretch,
- difference, totalDemerits, previous);
+ difference, totalDemerits, previous, variant);
}
/** {@inheritDoc} */
((BestPageRecords) best).getFootnoteElementIndex(fitness),
best.getAdjust(fitness), best.getAvailableShrink(fitness),
best.getAvailableStretch(fitness), best.getDifference(fitness),
- best.getDemerits(fitness), best.getNode(fitness));
+ best.getDemerits(fitness), best.getNode(fitness),
+ ((BestPageRecords) best).getVariant(fitness));
}
/**
/** {@inheritDoc} */
@Override
protected void considerLegalBreak(KnuthElement element, int elementIdx) {
+ variant = null;
if (element.isPenalty()) {
int breakClass = ((KnuthPenalty) element).getBreakClass();
switch (breakClass) {
int footnoteSplit;
boolean canDeferOldFN;
if (element.isPenalty()) {
- actualWidth += element.getWidth();
+ if (element instanceof BestFitPenalty) {
+ actualWidth += handleBestFitPenalty(activeNode, (BestFitPenalty) element, elementIndex);
+ } else {
+ actualWidth += element.getWidth();
+ }
}
if (footnotesPending) {
// compute the total length of the footnotes not yet inserted
}
}
+ private int handleBestFitPenalty(KnuthNode activeNode, BestFitPenalty penalty, int elementIndex) {
+ for (Variant var : penalty.getVariantList()) {
+ int difference = computeDifference(activeNode, var.toPenalty(), elementIndex);
+ double r = computeAdjustmentRatio(activeNode, difference);
+ if (r >= -1.0) {
+ variant = var;
+ return variant.width;
+ }
+ }
+ return 0;
+ }
+
/**
* Checks whether footnotes from preceding pages may be deferred to the page after
* the given element.
int total) {
//int difference = (bestActiveNode.line < total)
// ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth;
+ // Check if the given node has an attached dynamic content
+ KnuthPageNode pageNode = (KnuthPageNode) bestActiveNode;
+ if (pageNode.variant != null) {
+ BestFitPenalty penalty = (BestFitPenalty) par.get(pageNode.position);
+ penalty.activatePenalty(pageNode.variant);
+ }
int difference = bestActiveNode.difference;
if (difference + bestActiveNode.availableShrink < 0) {
if (!autoHeight) {