return breakBefore;
}
+ /** @return the "hyphenation-ladder-count" property. */
+ public Numeric getHyphenationLadderCount() {
+ return hyphenationLadderCount;
+ }
+
/** @return the "keep-with-next" property. */
public KeepProperty getKeepWithNext() {
return keepWithNext;
protected int repeatedFlaggedDemerit = 50;
// demerit for consecutive lines belonging to incompatible fitness classes
protected int incompatibleFitnessDemerit = 50;
+ // maximum number of consecutive lines ending with a flagged penalty
+ // only a value >= 1 is a significant limit
+ protected int maxFlaggedPenaltiesCount;
/**
* The threshold for considering breaks to be acceptable.
private boolean partOverflowRecoveryActivated = true;
public BreakingAlgorithm(int align, int alignLast,
- boolean first, boolean partOverflowRecovery) {
+ boolean first, boolean partOverflowRecovery,
+ int maxFlagCount) {
alignment = align;
alignmentLast = alignLast;
bFirst = first;
this.partOverflowRecoveryActivated = partOverflowRecovery;
this.best = new BestRecords();
+ maxFlaggedPenaltiesCount = maxFlagCount;
}
&& ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) {
// add demerit for consecutive breaks at flagged penalties
demerits += repeatedFlaggedDemerit;
+ // there are at least two consecutive lines ending with a flagged penalty;
+ // check if the previous line end with a flagged penalty too,
+ // and if this situation is allowed
+ int flaggedPenaltiesCount = 2;
+ for (KnuthNode prevNode = activeNode.previous;
+ prevNode != null && flaggedPenaltiesCount <= maxFlaggedPenaltiesCount;
+ prevNode = prevNode.previous) {
+ KnuthElement prevElement = getElement(prevNode.position);
+ if (prevElement.isPenalty()
+ && ((KnuthPenalty) prevElement).isFlagged()) {
+ // the previous line ends with a flagged penalty too
+ flaggedPenaltiesCount ++;
+ } else {
+ // the previous line does not end with a flagged penalty,
+ // exit the loop
+ break;
+ }
+ }
+ if (maxFlaggedPenaltiesCount >= 1
+ && flaggedPenaltiesCount > maxFlaggedPenaltiesCount) {
+ // add infinite demerits, so this break will not be chosen
+ // unless there isn't any alternative break
+ demerits += BestRecords.INFINITE_DEMERITS;
+ }
}
if (Math.abs(fitnessClass - activeNode.fitness) > 1) {
// add demerit for consecutive breaks
int alignment, int alignmentLast,
MinOptMax footnoteSeparatorLength,
boolean partOverflowRecovery) {
- super(alignment, alignmentLast, true, partOverflowRecovery);
+ super(alignment, alignmentLast, true, partOverflowRecovery, 0);
this.topLevelLM = topLevelLM;
this.pageViewportProvider = pageViewportProvider;
best = new BestPageRecords();
package org.apache.fop.layoutmgr.inline;
import org.apache.fop.datatypes.Length;
+import org.apache.fop.datatypes.Numeric;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.properties.CommonHyphenation;
import java.util.LinkedList;
import org.apache.fop.area.Trait;
import org.apache.fop.fonts.Font;
-import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode;
-import org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager.StackingIter;
import org.apache.fop.traits.MinOptMax;
textIndent = fobj.getTextIndent();
lastLineEndIndent = fobj.getLastLineEndIndent();
hyphenationProperties = fobj.getCommonHyphenation();
+ hyphenationLadderCount = fobj.getHyphenationLadderCount();
wrapOption = fobj.getWrapOption();
//
effectiveAlignment = getEffectiveAlignment(textAlignment, textAlignmentLast);
private Length lastLineEndIndent;
private int iIndents = 0;
private CommonHyphenation hyphenationProperties;
+ private Numeric hyphenationLadderCount;
private int wrapOption = EN_WRAP;
//private LayoutProps layoutProps;
int textAlign, int textAlignLast,
int indent, int fillerWidth,
int lh, int ld, int fl, boolean first,
- LineLayoutManager llm) {
- super(textAlign, textAlignLast, first, false);
+ int maxFlagCount, LineLayoutManager llm) {
+ super(textAlign, textAlignLast, first, false, maxFlagCount);
pageAlignment = pageAlign;
textIndent = indent;
fillerMinWidth = fillerWidth;
textIndent.getValue(this), currPar.lineFiller.opt,
lineHeight.getValue(this), lead, follow,
(knuthParagraphs.indexOf(currPar) == 0),
+ hyphenationLadderCount.getEnum() == EN_NO_LIMIT ?
+ 0 : hyphenationLadderCount.getValue(),
this);
if (hyphenationProperties.hyphenate == EN_TRUE) {
* @throws Exception if an error occurs
*/
public void test1() throws Exception {
- MyBreakingAlgorithm algo = new MyBreakingAlgorithm(0, 0, true, true);
+ MyBreakingAlgorithm algo = new MyBreakingAlgorithm(0, 0, true, true, 0);
algo.setConstantLineWidth(30000);
KnuthSequence seq = getKnuthSequence1();
algo.findBreakingPoints(seq, 1, true, BreakingAlgorithm.ALL_BREAKS);
private List parts = new java.util.ArrayList();
public MyBreakingAlgorithm(int align, int alignLast, boolean first,
- boolean partOverflowRecovery) {
- super(align, alignLast, first, partOverflowRecovery);
+ boolean partOverflowRecovery, int maxFlagCount) {
+ super(align, alignLast, first, partOverflowRecovery, maxFlagCount);
}
public Part[] getParts() {