aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/layoutmgr
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop/layoutmgr')
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java1
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java7
-rw-r--r--src/java/org/apache/fop/layoutmgr/KnuthSequence.java18
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutContext.java17
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java7
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java23
-rwxr-xr-xsrc/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java259
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java174
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java608
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java59
10 files changed, 756 insertions, 417 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index d091c73e5..cd011b366 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -187,6 +187,7 @@ public abstract class AbstractBreaker {
alignment = Constants.EN_START;
}
alignmentLast = Constants.EN_START;
+ childLC.setBPAlignment(alignment);
BlockSequence blockList;
blockLists = new java.util.ArrayList();
diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
index 636055cb5..45e2945fa 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
@@ -166,7 +166,10 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
*/
public boolean mustKeepTogether() {
//TODO Keeps will have to be more sophisticated sooner or later
- return ((BlockLevelLayoutManager)getParent()).mustKeepTogether()
+ // TODO This is a quick fix for the fact that the parent is not always a BlockLevelLM;
+ // eventually mustKeepTogether() must be moved up to the LM interface
+ return (getParent() instanceof BlockLevelLayoutManager
+ && ((BlockLevelLayoutManager) getParent()).mustKeepTogether())
|| !getBlockFO().getKeepTogether().getWithinPage().isAuto()
|| !getBlockFO().getKeepTogether().getWithinColumn().isAuto();
}
@@ -303,7 +306,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
splitLength += element.getW();
lastLM = element.getLayoutManager();
}
- }
+ }
//System.out.println("addAreas riferito a storedList da " +
// iFirst + " a " + iLast);
//System.out.println("splitLength= " + splitLength
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
index e757cb002..77f30f1c5 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
@@ -28,6 +28,8 @@ public class KnuthSequence extends ArrayList {
public int ignoreAtStart = 0;
/** Number of elements to ignore at the end of the list. */
public int ignoreAtEnd = 0;
+ // Is this an inline or a block sequence?
+ private boolean isInlineSequence = false;
/**
* Creates a new and empty list.
@@ -37,6 +39,14 @@ public class KnuthSequence extends ArrayList {
}
/**
+ * Creates a new and empty list, and sets isInlineSequence.
+ */
+ public KnuthSequence(boolean isInlineSequence) {
+ super();
+ this.isInlineSequence = isInlineSequence;
+ }
+
+ /**
* Marks the start of the sequence.
*/
public void startSequence() {
@@ -84,4 +94,12 @@ public class KnuthSequence extends ArrayList {
public KnuthElement getElement(int index) {
return (KnuthElement) get(index);
}
+
+ /**
+ * Is this an inline or a block sequence?
+ * @return true if this is an inline sequence
+ */
+ public boolean isInlineSequence() {
+ return isInlineSequence;
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutContext.java b/src/java/org/apache/fop/layoutmgr/LayoutContext.java
index 2d3323625..f63f23ccf 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutContext.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutContext.java
@@ -91,6 +91,9 @@ public class LayoutContext {
/** Current hyphenation context. May be null. */
private HyphContext hyphContext = null;
+ /** Alignment in BP direction */
+ private int bpAlignment = Constants.EN_START;
+
/** Stretch or shrink value when making areas. */
private double ipdAdjust = 0.0;
@@ -112,6 +115,7 @@ public class LayoutContext {
this.leadingSpace = parentLC.leadingSpace; //???
this.trailingSpace = parentLC.trailingSpace; //???
this.hyphContext = parentLC.hyphContext;
+ this.bpAlignment = parentLC.bpAlignment;
this.dSpaceAdjust = parentLC.dSpaceAdjust;
this.ipdAdjust = parentLC.ipdAdjust;
this.iLineHeight = parentLC.iLineHeight;
@@ -224,6 +228,19 @@ public class LayoutContext {
return ((this.flags & TRY_HYPHENATE) != 0);
}
+ /**
+ * Sets the currently applicable alignment in BP direction.
+ * @param alignment one of EN_START, EN_JUSTIFY etc.
+ */
+ public void setBPAlignment(int alignment) {
+ this.bpAlignment = alignment;
+ }
+
+ /** @return the currently applicable alignment in BP direction (EN_START, EN_JUSTIFY...) */
+ public int getBPAlignment() {
+ return this.bpAlignment;
+ }
+
public void setSpaceAdjust(double adjust) {
dSpaceAdjust = adjust;
}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
index 9dd0abbcb..c6d5c4bf7 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
@@ -20,6 +20,7 @@ package org.apache.fop.layoutmgr.inline;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.area.inline.InlineArea;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.Trait;
import org.apache.fop.area.LinkResolver;
@@ -41,14 +42,14 @@ public class BasicLinkLayoutManager extends InlineLayoutManager {
fobj = node;
}
- protected InlineParent createArea() {
- InlineParent area = super.createArea();
+ protected InlineArea createArea(boolean bInlineParent) {
+ InlineArea area = super.createArea(bInlineParent);
setupBasicLinkArea(parentLM, area);
return area;
}
private void setupBasicLinkArea(LayoutManager parentLM,
- InlineParent area) {
+ InlineArea area) {
if (fobj.getExternalDestination() != null) {
area.addTrait(Trait.EXTERNAL_LINK, fobj.getExternalDestination());
} else {
diff --git a/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java
index e39292f62..779c4c587 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java
@@ -26,6 +26,7 @@ import org.apache.fop.fo.flow.Footnote;
import org.apache.fop.layoutmgr.AbstractLayoutManager;
import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.Position;
@@ -45,7 +46,7 @@ public class FootnoteLayoutManager extends AbstractLayoutManager
footnote = node;
// create an InlineStackingLM handling the fo:inline child of fo:footnote
- citationLM = new InlineStackingLayoutManager(footnote.getFootnoteCitation());
+ citationLM = new InlineLayoutManager(footnote.getFootnoteCitation());
// create a FootnoteBodyLM handling the fo:footnote-body child of fo:footnote
bodyLM = new FootnoteBodyLayoutManager(footnote.getFootnoteBody());
@@ -85,12 +86,24 @@ public class FootnoteLayoutManager extends AbstractLayoutManager
private void addAnchor(LinkedList citationList) {
// find the last box in the sequence, and add a reference
// to the FootnoteBodyLM
- ListIterator citationIterator = citationList.listIterator(citationList.size());
KnuthInlineBox lastBox = null;
+ ListIterator citationIterator = citationList.listIterator(citationList.size());
while (citationIterator.hasPrevious() && lastBox == null) {
- KnuthElement element = (KnuthElement) citationIterator.previous();
- if (element instanceof KnuthInlineBox) {
- lastBox = (KnuthInlineBox) element;
+ Object obj = citationIterator.previous();
+ if (obj instanceof KnuthElement) {
+ KnuthElement element = (KnuthElement)obj;
+ if (element instanceof KnuthInlineBox) {
+ lastBox = (KnuthInlineBox) element;
+ }
+ } else {
+ KnuthSequence seq = (KnuthSequence)obj;
+ ListIterator nestedIterator = seq.listIterator(seq.size());
+ while (nestedIterator.hasPrevious() && lastBox == null) {
+ KnuthElement element = (KnuthElement)nestedIterator.previous();
+ if (element instanceof KnuthInlineBox) {
+ lastBox = (KnuthInlineBox) element;
+ }
+ }
}
}
if (lastBox != null) {
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
index 7f0943a9f..72b8c7bad 100755
--- a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
@@ -21,6 +21,9 @@ package org.apache.fop.layoutmgr.inline;
import java.util.ListIterator;
import java.util.LinkedList;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InlineLevel;
@@ -28,10 +31,14 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonMarginInline;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
+import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.SpaceSpecifier;
import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.traits.SpaceVal;
@@ -46,6 +53,9 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
private CommonMarginInline inlineProps = null;
private CommonBorderPaddingBackground borderProps = null;
+ private boolean bAreaCreated = false;
+ private LayoutManager lastChildLM = null; // Set when return last breakposs;
+
/**
* Create an inline layout manager.
* This is used for fo's that create areas that
@@ -109,8 +119,14 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
}
/** @see org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager#createArea() */
- protected InlineParent createArea() {
- InlineParent area = super.createArea();
+ protected InlineArea createArea(boolean bInlineParent) {
+ InlineArea area;
+ if (bInlineParent) {
+ area = new InlineParent();
+ area.setOffset(0);
+ } else {
+ area = new InlineBlockParent();
+ }
TraitSetter.setProducerID(area, getInlineFO().getId());
return area;
}
@@ -132,7 +148,8 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
/** @see org.apache.fop.layoutmgr.LayoutManager */
public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
- InlineLevelLayoutManager curLM;
+ InlineLevelLayoutManager curILM;
+ LayoutManager curLM, lastLM = null;
// the list returned by child LM
LinkedList returnedList;
@@ -140,6 +157,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
// the list which will be returned to the parent LM
LinkedList returnList = new LinkedList();
+ KnuthSequence lastSequence = null;
SpaceSpecifier leadingSpace = lc.getLeadingSpace();
@@ -160,27 +178,236 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
clearPrevIPD(); // Clear stored prev content dimensions
}
- while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
+ StringBuffer trace = new StringBuffer("InlineLM:");
+
+ while ((curLM = (LayoutManager) getChildLM()) != null) {
// get KnuthElements from curLM
returnedList = curLM.getNextKnuthElements(lc, alignment);
- if (returnedList != null) {
+ if (returnedList == null) {
+ // curLM returned null because it finished;
+ // just iterate once more to see if there is another child
+ continue;
+ }
+ if (curLM instanceof InlineLevelLayoutManager) {
+ // close the last block sequence
+ if (lastSequence != null && !lastSequence.isInlineSequence()) {
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
// "wrap" the Position stored in each element of returnedList
- ListIterator listIter = returnedList.listIterator();
- while (listIter.hasNext()) {
- returnedElement = (KnuthElement) listIter.next();
- returnedElement.setPosition
+ ListIterator seqIter = returnedList.listIterator();
+ while (seqIter.hasNext()) {
+ KnuthSequence sequence = (KnuthSequence) seqIter.next();
+ ListIterator listIter = sequence.listIterator();
+ while (listIter.hasNext()) {
+ returnedElement = (KnuthElement) listIter.next();
+ returnedElement.setPosition
(new NonLeafPosition(this,
- returnedElement.getPosition()));
- returnList.add(returnedElement);
+ returnedElement.getPosition()));
+ }
+ if (!sequence.isInlineSequence()) {
+ if (lastSequence != null && lastSequence.isInlineSequence()) {
+ // log.error("Last inline sequence should be closed before a block sequence");
+ lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, null, false));
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ returnList.add(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" B");
+ }
+ } else {
+ if (lastSequence == null) {
+ lastSequence = new KnuthSequence(true);
+ returnList.add(lastSequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ lastSequence.addAll(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" I");
+ }
+ // finish last paragraph if it was closed with a linefeed
+ KnuthElement lastElement = (KnuthElement) sequence.getLast();
+ if (lastElement.isPenalty()
+ && ((KnuthPenalty) lastElement).getP()
+ == -KnuthPenalty.INFINITE) {
+ // a penalty item whose value is -inf
+ // represents a preserved linefeed,
+ // wich forces a line break
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ }
+ }
+ } else { // A block LM
+ // close the last inline sequence
+ if (lastSequence != null && lastSequence.isInlineSequence()) {
+ lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, null, false));
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ if (curLM != lastLM) {
+ // close the last block sequence
+ if (lastSequence != null && !lastSequence.isInlineSequence()) {
+ lastSequence = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ lastLM = curLM;
+ }
+ if (lastSequence == null) {
+ lastSequence = new KnuthSequence(false);
+ returnList.add(lastSequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ ListIterator iter = returnedList.listIterator();
+ while (iter.hasNext()) {
+ KnuthElement element = (KnuthElement) iter.next();
+ element.setPosition
+ (new NonLeafPosition(this,
+ element.getPosition()));
+ }
+ lastSequence.addAll(returnedList);
+ if (log.isTraceEnabled()) {
+ trace.append(" L");
}
- return returnList;
- } else {
- // curLM returned null because it finished;
- // just iterate once more to see if there is another child
}
}
setFinished(true);
- return null;
+ log.trace(trace);
+ return returnList.size() == 0 ? null : returnList;
+ }
+
+ /**
+ * Generate and add areas to parent area.
+ * Set size of each area. This should only create and return one
+ * inline area for any inline parent area.
+ *
+ * @param parentIter Iterator over Position information returned
+ * by this LayoutManager.
+ * @param dSpaceAdjust Factor controlling how much extra space to add
+ * in order to justify the line.
+ */
+ public void addAreas(PositionIterator parentIter,
+ LayoutContext context) {
+ addId();
+
+ setChildContext(new LayoutContext(context)); // Store current value
+
+ // If has fence, make a new leadingSS
+ /* How to know if first area created by this LM? Keep a count and
+ * reset it if getNextBreakPoss() is called again.
+ */
+ if (hasLeadingFence(bAreaCreated)) {
+ getContext().setLeadingSpace(new SpaceSpecifier(false));
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+ true);
+ } else {
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+ false);
+ }
+
+ if (getSpaceStart() != null) {
+ context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
+ }
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ // also set lastLM to be the LayoutManager which created
+ // the last Position: if the LAST_AREA flag is set in context,
+ // it must be also set in the LayoutContext given to lastLM,
+ // but unset in the LayoutContext given to the other LMs
+ LinkedList positionList = new LinkedList();
+ NonLeafPosition pos = null;
+ LayoutManager lastLM = null; // last child LM in this iterator
+ while (parentIter.hasNext()) {
+ pos = (NonLeafPosition) parentIter.next();
+ positionList.add(pos.getPosition());
+ }
+ if (pos != null) {
+ lastLM = pos.getPosition().getLM();
+ }
+
+ InlineArea parent = createArea(lastLM == null || lastLM instanceof InlineLevelLayoutManager);
+ parent.setBPD(context.getLineHeight());
+ setCurrentArea(parent);
+
+ StackingIter childPosIter
+ = new StackingIter(positionList.listIterator());
+
+ LayoutManager prevLM = null;
+ LayoutManager childLM;
+ while ((childLM = childPosIter.getNextChildLM())
+ != null) {
+ getContext().setFlags(LayoutContext.LAST_AREA,
+ context.isLastArea() && childLM == lastLM);
+ childLM.addAreas(childPosIter, getContext());
+ getContext().setLeadingSpace(getContext().getTrailingSpace());
+ getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+ prevLM = childLM;
+ }
+
+ /* If has trailing fence,
+ * resolve trailing space specs from descendants.
+ * Otherwise, propagate any trailing space specs to parent LM via
+ * the context object.
+ * If the last child LM called return ISLAST in the context object
+ * and it is the last child LM for this LM, then this must be
+ * the last area for the current LM also.
+ */
+ boolean bIsLast =
+ (getContext().isLastArea() && prevLM == lastChildLM);
+ if (hasTrailingFence(bIsLast)) {
+ addSpace(getCurrentArea(),
+ getContext().getTrailingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ context.setTrailingSpace(new SpaceSpecifier(false));
+ } else {
+ // Propagate trailing space-spec sequence to parent LM in context
+ context.setTrailingSpace(getContext().getTrailingSpace());
+ }
+ // Add own trailing space to parent context (or set on area?)
+ if (context.getTrailingSpace() != null && getSpaceEnd() != null) {
+ context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
+ }
+ setTraits(bAreaCreated, !bIsLast);
+
+ parentLM.addChildArea(getCurrentArea());
+ context.setFlags(LayoutContext.LAST_AREA, bIsLast);
+ bAreaCreated = true;
+ }
+
+ public void addChildArea(Area childArea) {
+ Area parent = getCurrentArea();
+ if (getContext().resolveLeadingSpace()) {
+ addSpace(parent,
+ getContext().getLeadingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ }
+ parent.addChildArea(childArea);
}
/*
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
index 0b05cc8aa..eb8eab717 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
@@ -33,11 +33,7 @@ import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
-import org.apache.fop.layoutmgr.SpaceSpecifier;
-import org.apache.fop.traits.SpaceVal;
import org.apache.fop.area.Area;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.InlineParent;
import org.apache.fop.area.inline.Space;
import org.apache.fop.traits.MinOptMax;
@@ -50,7 +46,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
implements InlineLevelLayoutManager {
- private static class StackingIter extends PositionIterator {
+ protected static class StackingIter extends PositionIterator {
StackingIter(Iterator parentIter) {
super(parentIter);
@@ -81,7 +77,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
//private BreakPoss prevBP;
protected LayoutContext childLC;
- private LayoutManager lastChildLM = null; // Set when return last breakposs
private boolean bAreaCreated = false;
//private LayoutManager currentLM = null;
@@ -177,10 +172,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
hmPrevIPD.clear();
}
- protected InlineParent createArea() {
- return new InlineParent();
- }
-
/**
* This method is called by addAreas() so IDs can be added to a page for FOs that
* support the 'id' property.
@@ -189,103 +180,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
// Do nothing here, overriden in subclasses that have an 'id' property.
}
- /**
- * Generate and add areas to parent area.
- * Set size of each area. This should only create and return one
- * inline area for any inline parent area.
- *
- * @param parentIter Iterator over Position information returned
- * by this LayoutManager.
- * @param dSpaceAdjust Factor controlling how much extra space to add
- * in order to justify the line.
- */
- public void addAreas(PositionIterator parentIter,
- LayoutContext context) {
- addId();
- InlineParent parent = createArea();
- parent.setBPD(context.getLineHeight());
- parent.setOffset(0);
- setCurrentArea(parent);
-
- setChildContext(new LayoutContext(context)); // Store current value
-
- // If has fence, make a new leadingSS
- /* How to know if first area created by this LM? Keep a count and
- * reset it if getNextBreakPoss() is called again.
- */
- if (hasLeadingFence(bAreaCreated)) {
- getContext().setLeadingSpace(new SpaceSpecifier(false));
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
- true);
- } else {
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
- false);
- }
-
- if (getSpaceStart() != null) {
- context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
- }
-
- // "unwrap" the NonLeafPositions stored in parentIter
- // and put them in a new list;
- // also set lastLM to be the LayoutManager which created
- // the last Position: if the LAST_AREA flag is set in context,
- // it must be also set in the LayoutContext given to lastLM,
- // but unset in the LayoutContext given to the other LMs
- LinkedList positionList = new LinkedList();
- NonLeafPosition pos;
- LayoutManager lastLM = null; // last child LM in this iterator
- while (parentIter.hasNext()) {
- pos = (NonLeafPosition) parentIter.next();
- lastLM = pos.getPosition().getLM();
- positionList.add(pos.getPosition());
- }
-
- StackingIter childPosIter
- = new StackingIter(positionList.listIterator());
-
- LayoutManager prevLM = null;
- InlineLevelLayoutManager childLM;
- while ((childLM = (InlineLevelLayoutManager) childPosIter.getNextChildLM())
- != null) {
- getContext().setFlags(LayoutContext.LAST_AREA,
- context.isLastArea() && childLM == lastLM);
- childLM.addAreas(childPosIter, getContext());
- getContext().setLeadingSpace(getContext().getTrailingSpace());
- getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
- prevLM = childLM;
- }
-
- /* If has trailing fence,
- * resolve trailing space specs from descendants.
- * Otherwise, propagate any trailing space specs to parent LM via
- * the context object.
- * If the last child LM called return ISLAST in the context object
- * and it is the last child LM for this LM, then this must be
- * the last area for the current LM also.
- */
- boolean bIsLast =
- (getContext().isLastArea() && prevLM == lastChildLM);
- if (hasTrailingFence(bIsLast)) {
- addSpace(getCurrentArea(),
- getContext().getTrailingSpace().resolve(false),
- getContext().getSpaceAdjust());
- context.setTrailingSpace(new SpaceSpecifier(false));
- } else {
- // Propagate trailing space-spec sequence to parent LM in context
- context.setTrailingSpace(getContext().getTrailingSpace());
- }
- // Add own trailing space to parent context (or set on area?)
- if (context.getTrailingSpace() != null && getSpaceEnd() != null) {
- context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
- }
- setTraits(bAreaCreated, !bIsLast);
-
- parentLM.addChildArea(getCurrentArea());
- context.setFlags(LayoutContext.LAST_AREA, bIsLast);
- bAreaCreated = true;
- }
-
protected Area getCurrentArea() {
return currentArea;
}
@@ -298,19 +192,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
}
- public void addChildArea(Area childArea) {
- // Make sure childArea is inline area
- if (childArea instanceof InlineArea) {
- Area parent = getCurrentArea();
- if (getContext().resolveLeadingSpace()) {
- addSpace(parent,
- getContext().getLeadingSpace().resolve(false),
- getContext().getSpaceAdjust());
- }
- parent.addChildArea(childArea);
- }
- }
-
protected void setChildContext(LayoutContext lc) {
childLC = lc;
}
@@ -342,57 +223,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
}
}
- public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
- InlineLevelLayoutManager curLM;
-
- // the list returned by child LM
- LinkedList returnedList;
- KnuthElement returnedElement;
-
- // the list which will be returned to the parent LM
- LinkedList returnList = new LinkedList();
-
- SpaceSpecifier leadingSpace = lc.getLeadingSpace();
-
- if (lc.startsNewArea()) {
- // First call to this LM in new parent "area", but this may
- // not be the first area created by this inline
- childLC = new LayoutContext(lc);
- lc.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
-
- // Check for "fence"
- if (hasLeadingFence(!lc.isFirstArea())) {
- // Reset leading space sequence for child areas
- leadingSpace = new SpaceSpecifier(false);
- }
- // Reset state variables
- clearPrevIPD(); // Clear stored prev content dimensions
- }
-
- while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
- // get KnuthElements from curLM
- returnedList = curLM.getNextKnuthElements(lc, alignment);
- if (returnedList != null) {
- // "wrap" the Position stored in each element of returnedList
- ListIterator listIter = returnedList.listIterator();
- while (listIter.hasNext()) {
- returnedElement = (KnuthElement) listIter.next();
- returnedElement.setPosition
- (new NonLeafPosition(this,
- returnedElement.getPosition()));
- returnList.add(returnedElement);
- }
- setFinished(curLM.isFinished() && (getChildLM() == null));
- return returnList;
- } else {
- // curLM returned null because it finished;
- // just iterate once more to see if there is another child
- }
- }
- setFinished(true);
- return null;
- }
-
public List addALetterSpaceTo(List oldList) {
// old list contains only a box, or the sequence: box penalty glue box
@@ -407,7 +237,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
oldList = ((InlineLevelLayoutManager)
element.getLayoutManager()).addALetterSpaceTo(oldList);
- // "wrap" againg the Position stored in each element of oldList
+ // "wrap" again the Position stored in each element of oldList
oldListIterator = oldList.listIterator();
while (oldListIterator.hasNext()) {
element = (KnuthElement) oldListIterator.next();
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index c3091d66c..f51e6af2b 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
@@ -37,10 +37,13 @@ import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.area.Area;
import org.apache.fop.area.LineArea;
+import org.apache.fop.area.inline.InlineArea;
import java.util.ListIterator;
import java.util.List;
@@ -184,7 +187,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
int indent) {
- super();
+ super(true);
layoutManager = llm;
textAlignment = alignment;
textAlignmentLast = alignmentLast;
@@ -268,6 +271,40 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}
}
+ private void addALetterSpace() {
+ KnuthBox prevBox = (KnuthBox) removeLast();
+ LinkedList oldList = new LinkedList();
+ // if there are two consecutive KnuthBoxes the
+ // first one does not represent a whole word,
+ // so it must be given one more letter space
+ if (!prevBox.isAuxiliary()) {
+ // if letter spacing is constant,
+ // only prevBox needs to be replaced;
+ oldList.add(prevBox);
+ } else {
+ // prevBox is the last element
+ // in the sub-sequence
+ // <box> <aux penalty> <aux glue> <aux box>
+ // the letter space is added to <aux glue>,
+ // while the other elements are not changed
+ oldList.add(prevBox);
+ oldList.addFirst((KnuthGlue) removeLast());
+ oldList.addFirst((KnuthPenalty) removeLast());
+ oldList.addFirst((KnuthBox) removeLast());
+ }
+ // adding a letter space could involve, according to the text
+ // represented by oldList, replacing a glue element or adding
+ // new elements
+ addAll(((InlineLevelLayoutManager)
+ prevBox.getLayoutManager())
+ .addALetterSpaceTo(oldList));
+ if (((KnuthInlineBox) prevBox).isAnchor()) {
+ // prevBox represents a footnote citation: copy footnote info
+ // from prevBox to the new box
+ KnuthInlineBox newBox = (KnuthInlineBox) getLast();
+ newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+ }
+ }
}
private class LineBreakingAlgorithm extends BreakingAlgorithm {
@@ -510,6 +547,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
initialize(); // Normally done when started by parent!
}
+ /** @see org.apache.fop.layoutmgr.LayoutManager */
public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
// Get a break from currently active child LM
// Set up constraints for inline level managers
@@ -546,7 +584,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}
//PHASE 2: Create line breaks
- return findOptimalLineBreakingPoints(alignment);
+ return createLineBreaks(context.getBPAlignment());
/*
LineBreakPosition lbp = null;
if (breakpoints == null) {
@@ -586,19 +624,17 @@ public class LineLayoutManager extends InlineStackingLayoutManager
LayoutContext inlineLC = new LayoutContext(context);
InlineLevelLayoutManager curLM;
- KnuthElement thisElement = null;
LinkedList returnedList = null;
iLineWidth = context.getStackLimit().opt;
// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
boolean bPrevWasKnuthBox = false;
- KnuthBox prevBox = null;
- Paragraph knuthPar = new Paragraph(this,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue());
- knuthPar.startParagraph(availIPD.opt);
+ StringBuffer trace = new StringBuffer("LineLM:");
+
+ Paragraph lastPar = null;
+
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
if ((returnedList
= curLM.getNextKnuthElements(inlineLC,
@@ -607,78 +643,119 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (returnedList.size() == 0) {
continue;
}
- // look at the first element
- thisElement = (KnuthElement) returnedList.getFirst();
- if (thisElement.isBox() && !thisElement.isAuxiliary()
- && bPrevWasKnuthBox) {
- prevBox = (KnuthBox) knuthPar.removeLast();
- LinkedList oldList = new LinkedList();
- // if there are two consecutive KnuthBoxes the
- // first one does not represent a whole word,
- // so it must be given one more letter space
- if (!prevBox.isAuxiliary()) {
- // if letter spacing is constant,
- // only prevBox needs to be replaced;
- oldList.add(prevBox);
+ // does the first element of the first paragraph add to an existing word?
+ if (lastPar != null) {
+ Object obj = returnedList.getFirst();
+ KnuthElement thisElement;
+ if (obj instanceof KnuthElement) {
+ thisElement = (KnuthElement)obj;
} else {
- // prevBox is the last element
- // in the sub-sequence
- // <box> <aux penalty> <aux glue> <aux box>
- // the letter space is added to <aux glue>,
- // while the other elements are not changed
- oldList.add(prevBox);
- oldList.addFirst((KnuthGlue) knuthPar.removeLast());
- oldList.addFirst((KnuthPenalty) knuthPar.removeLast());
- oldList.addFirst((KnuthBox) knuthPar.removeLast());
+ KnuthSequence firstSeq = (KnuthSequence) obj;
+ if (!firstSeq.isInlineSequence()) {
+ log.error("Expect inline sequence as first sequence when last paragraph is not null");
+ }
+ thisElement = (KnuthElement) firstSeq.get(0);
}
- // adding a letter space could involve, according to the text
- // represented by oldList, replacing a glue element or adding
- // new elements
- knuthPar.addAll(((InlineLevelLayoutManager)
- prevBox.getLayoutManager())
- .addALetterSpaceTo(oldList));
- if (((KnuthInlineBox) prevBox).isAnchor()) {
- // prevBox represents a footnote citation: copy footnote info
- // from prevBox to the new box
- KnuthInlineBox newBox = (KnuthInlineBox) knuthPar.getLast();
- newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+ if (thisElement.isBox() && !thisElement.isAuxiliary()
+ && bPrevWasKnuthBox) {
+ lastPar.addALetterSpace();
}
}
- // look at the last element
- KnuthElement lastElement = (KnuthElement) returnedList.getLast();
- boolean bForceLinefeed = false;
- if (lastElement.isBox()) {
- bPrevWasKnuthBox = true;
- } else {
- bPrevWasKnuthBox = false;
- if (lastElement.isPenalty()
- && ((KnuthPenalty) lastElement).getP()
- == -KnuthPenalty.INFINITE) {
- // a penalty item whose value is -inf
- // represents a preserved linefeed,
- // wich forces a line break
- bForceLinefeed = true;
- returnedList.removeLast();
+ // loop over the KnuthSequences (and single KnuthElements) in returnedList
+ // (LeafNodeLM descendants may also skip wrapping elements in KnuthSequences
+ // to cause fewer container structures)
+ // TODO the mixture here adds a little to the complexity. Decide whether:
+ // - to leave as is and save some container instances
+ // - to use KnuthSequences exclusively (adjustments on leaf-type LMs necessary)
+ // See also FootnoteLM.addAnchor() as well as right above this comment
+ // for similar code. Or see http://svn.apache.org/viewcvs?rev=230779&view=rev
+ ListIterator iter = returnedList.listIterator();
+ while (iter.hasNext()) {
+ Object obj = iter.next();
+ KnuthElement singleElement = null;
+ KnuthSequence sequence = null;
+ if (obj instanceof KnuthElement) {
+ singleElement = (KnuthElement)obj;
+ } else {
+ sequence = (KnuthSequence)obj;
}
- }
+ // the sequence contains inline Knuth elements
+ if (singleElement != null || sequence.isInlineSequence()) {
+ // look at the last element
+ KnuthElement lastElement;
+ if (singleElement != null) {
+ lastElement = singleElement;
+ } else {
+ lastElement = (KnuthElement) sequence.getLast();
+ if (lastElement == null) {
+ throw new NullPointerException(
+ "Sequence was empty! lastElement is null");
+ }
+ }
+ bPrevWasKnuthBox = lastElement.isBox();
+
+ // if last paragraph is open, add the new elements to the paragraph
+ // else this is the last paragraph
+ if (lastPar == null) {
+ lastPar = new Paragraph(this,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue());
+ lastPar.startParagraph(availIPD.opt);
+ if (log.isTraceEnabled()) {
+ trace.append(" [");
+ }
+ } else {
+ if (log.isTraceEnabled()) {
+ trace.append(" +");
+ }
+ }
+ if (singleElement != null) {
+ lastPar.add(singleElement);
+ } else {
+ lastPar.addAll(sequence);
+ }
+ if (log.isTraceEnabled()) {
+ trace.append(" I");
+ }
- // add the new elements to the paragraph
- knuthPar.addAll(returnedList);
- if (bForceLinefeed) {
- if (knuthPar.size() == 0) {
- //only a forced linefeed on this line
- //-> compensate with a zero width box
- knuthPar.add(new KnuthInlineBox(0, 0, 0, 0,
- null, false));
+ // finish last paragraph if it was closed with a linefeed
+ if (lastElement.isPenalty()
+ && ((KnuthPenalty) lastElement).getP()
+ == -KnuthPenalty.INFINITE) {
+ // a penalty item whose value is -inf
+ // represents a preserved linefeed,
+ // wich forces a line break
+ lastPar.removeLast();
+ if (lastPar.size() == 0) {
+ //only a forced linefeed on this line
+ //-> compensate with a zero width box
+ lastPar.add(new KnuthInlineBox(0, 0, 0, 0,
+ null, false));
+ }
+ lastPar.endParagraph();
+ ElementListObserver.observe(lastPar, "line", null);
+ lastPar = null;
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ bPrevWasKnuthBox = false;
+ }
+ } else { // the sequence is a block sequence
+/* // "wrap" the Position stored in each element of returnedList
+ ListIterator listIter = sequence.listIterator();
+ while (listIter.hasNext()) {
+ KnuthElement returnedElement = (KnuthElement) listIter.next();
+ returnedElement.setPosition
+ (new NonLeafPosition(this,
+ returnedElement.getPosition()));
+ }
+*/ knuthParagraphs.add(sequence);
+ if (log.isTraceEnabled()) {
+ trace.append(" B");
+ }
}
- knuthPar.endParagraph();
- knuthPar = new Paragraph(this,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue());
- knuthPar.startParagraph(availIPD.opt);
- bPrevWasKnuthBox = false;
- }
+ } // end of loop over returnedList
} else {
// curLM returned null; this can happen
// if it has nothing more to layout,
@@ -686,8 +763,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// if there are other children
}
}
- knuthPar.endParagraph();
- ElementListObserver.observe(knuthPar, "line", null);
+ if (lastPar != null) {
+ lastPar.endParagraph();
+ ElementListObserver.observe(lastPar, "line", null);
+ if (log.isTraceEnabled()) {
+ trace.append(" ]");
+ }
+ }
+ log.trace(trace);
}
/**
@@ -822,121 +905,167 @@ public class LineLayoutManager extends InlineStackingLayoutManager
/**
* Phase 2 of Knuth algorithm: find optimal break points.
- * @param alignment alignmenr of the paragraph
+ * @param alignment alignment in BP direction of the paragraph
* @return a list of Knuth elements representing broken lines
*/
- private LinkedList findOptimalLineBreakingPoints(int alignment) {
+ private LinkedList createLineBreaks(int alignment) {
// find the optimal line breaking points for each paragraph
ListIterator paragraphsIterator
= knuthParagraphs.listIterator(knuthParagraphs.size());
- Paragraph currPar = null;
- LineBreakingAlgorithm alg;
lineLayoutsList = new ArrayList(knuthParagraphs.size());
while (paragraphsIterator.hasPrevious()) {
- lineLayouts = new LineLayoutPossibilities();
- currPar = (Paragraph) paragraphsIterator.previous();
- double maxAdjustment = 1;
- int iBPcount = 0;
- alg = new LineBreakingAlgorithm(alignment,
- bTextAlignment, bTextAlignmentLast,
- textIndent.getValue(), currPar.lineFiller.opt,
- lineHeight, lead, follow, middleShift,
- (knuthParagraphs.indexOf(currPar) == 0),
- this);
-
- if (hyphProps.hyphenate == EN_TRUE) {
- findHyphenationPoints(currPar);
- }
-
- // first try
- boolean bHyphenationAllowed = false;
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, false, bHyphenationAllowed);
- if (iBPcount == 0 || alignment == EN_JUSTIFY) {
- // if the first try found a set of breaking points, save them
- if (iBPcount > 0) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(false);
- } else {
- // the first try failed
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
- }
-
- // now try something different
- log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
- if (hyphProps.hyphenate == EN_TRUE) {
- // consider every hyphenation point as a legal break
- bHyphenationAllowed = true;
- } else {
- // try with a higher threshold
- maxAdjustment = 5;
- }
-
- if ((iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, false, bHyphenationAllowed)) == 0) {
- // the second try failed too, try with a huge threshold
- // and force the algorithm to find
- // a set of breaking points
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
- + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
- maxAdjustment = 20;
- iBPcount
- = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- }
-
- // use non-hyphenated breaks, when possible
- lineLayouts.restorePossibilities();
-
- /* extension (not in the XSL FO recommendation): if vertical alignment
- is justify and the paragraph has only one layout, try using
- shorter or longer lines */
- //TODO This code snippet is disabled. Reenable?
- if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
- //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
- //System.out.println(" layouts with fewer lines? " + lineLayouts.canUseLessLines());
- if (!lineLayouts.canUseMoreLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with shorter lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 0.95);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- if (!lineLayouts.canUseLessLines()) {
- alg.resetAlgorithm();
- lineLayouts.savePossibilities(true);
- // try with longer lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 1.05);
- alg.setConstantLineWidth(iLineWidth);
- iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, bHyphenationAllowed);
- // use normal lines, when possible
- lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
- }
- //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
- //System.out.println(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
- }
+ KnuthSequence seq = (KnuthSequence) paragraphsIterator.previous();
+ if (!seq.isInlineSequence()) {
+ lineLayouts = createBlockLineBreak(seq);
+ } else {
+ lineLayouts = findOptimalBreakingPoints(alignment, (Paragraph) seq);
}
lineLayoutsList.add(0, lineLayouts);
}
-
setFinished(true);
//Post-process the line breaks found
return postProcessLineBreaks(alignment);
}
+ /**
+ * create a single line layout possibility with a single linebreak
+ * for a block sequence
+ * @param seq the Knuth sequence for which the linebreak is created
+ * @return the line layout possibilities for the paragraph
+ */
+ private LineLayoutPossibilities createBlockLineBreak(KnuthSequence seq) {
+ //TODO Should this really create only a single LineBreakPosition???
+ //This creates an implicit keep-together on the nested block-level FOs.
+ lineLayouts = new LineLayoutPossibilities();
+ lineLayouts.addPossibility(1,0);
+ int lineHeight = 0, lineStretch = 0, lineShrink = 0;
+ ListIterator seqIterator = seq.listIterator();
+ while (seqIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) seqIterator.next();
+ lineHeight += element.getW();
+ if (element.isGlue()) {
+ lineStretch += element.getY();
+ lineShrink += element.getZ();
+ }
+ }
+ LineBreakPosition lbp = new LineBreakPosition(this,
+ knuthParagraphs.indexOf(seq), seq.size() - 1,
+ lineShrink, lineStretch, 0, 0, 0, 0, lineHeight,
+ iLineWidth, 0, 0, 0);
+ lineLayouts.addBreakPosition(lbp, 0);
+ return lineLayouts;
+ }
+
+ /**
+ * Fint the optimal linebreaks for a paragraph
+ * @param alignment alignment of the paragraph
+ * @param currPar the Paragraph for which the linebreaks are found
+ * @return the line layout possibilities for the paragraph
+ */
+ private LineLayoutPossibilities findOptimalBreakingPoints(int alignment, Paragraph currPar) {
+ lineLayouts = new LineLayoutPossibilities();
+ double maxAdjustment = 1;
+ int iBPcount = 0;
+ LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment,
+ bTextAlignment, bTextAlignmentLast,
+ textIndent.getValue(), currPar.lineFiller.opt,
+ lineHeight, lead, follow, middleShift,
+ (knuthParagraphs.indexOf(currPar) == 0),
+ this);
+
+ if (hyphProps.hyphenate == EN_TRUE) {
+ findHyphenationPoints(currPar);
+ }
+
+ // first try
+ boolean bHyphenationAllowed = false;
+ alg.setConstantLineWidth(iLineWidth);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, false, bHyphenationAllowed);
+ if (iBPcount == 0 || alignment == EN_JUSTIFY) {
+ // if the first try found a set of breaking points, save them
+ if (iBPcount > 0) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(false);
+ } else {
+ // the first try failed
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
+ }
+
+ // now try something different
+ log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
+ if (hyphProps.hyphenate == EN_TRUE) {
+ // consider every hyphenation point as a legal break
+ bHyphenationAllowed = true;
+ } else {
+ // try with a higher threshold
+ maxAdjustment = 5;
+ }
+
+ if ((iBPcount
+ = alg.findBreakingPoints(currPar,
+ maxAdjustment, false, bHyphenationAllowed)) == 0) {
+ // the second try failed too, try with a huge threshold
+ // and force the algorithm to find
+ // a set of breaking points
+ log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+ + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
+ maxAdjustment = 20;
+ iBPcount
+ = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ }
+
+ // use non-hyphenated breaks, when possible
+ lineLayouts.restorePossibilities();
+
+ /* extension (not in the XSL FO recommendation): if vertical alignment
+ is justify and the paragraph has only one layout, try using
+ shorter or longer lines */
+ //TODO This code snippet is disabled. Reenable?
+ if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
+ //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
+ //System.out.println(" layouts with fewer lines? " + lineLayouts.canUseLessLines());
+ if (!lineLayouts.canUseMoreLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with shorter lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 0.95);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+ if (!lineLayouts.canUseLessLines()) {
+ alg.resetAlgorithm();
+ lineLayouts.savePossibilities(true);
+ // try with longer lines
+ int savedLineWidth = iLineWidth;
+ iLineWidth = (int) (iLineWidth * 1.05);
+ alg.setConstantLineWidth(iLineWidth);
+ iBPcount = alg.findBreakingPoints(currPar,
+ maxAdjustment, true, bHyphenationAllowed);
+ // use normal lines, when possible
+ lineLayouts.restorePossibilities();
+ iLineWidth = savedLineWidth;
+ }
+ //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
+ //System.out.println(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
+ }
+ }
+ return lineLayouts;
+ }
+
+ /**
+ * Creates the element list in BP direction for the broken lines.
+ * @param alignment the currently applicable vertical alignment
+ * @return the newly built element list
+ */
private LinkedList postProcessLineBreaks(int alignment) {
LinkedList returnList = new LinkedList();
@@ -949,8 +1078,22 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}
lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
-
- if (alignment == EN_JUSTIFY) {
+ KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(p);
+
+ if (!seq.isInlineSequence()) {
+ LinkedList targetList = new LinkedList();
+ ListIterator listIter = seq.listIterator();
+ while (listIter.hasNext()) {
+ KnuthElement tempElement;
+ tempElement = (KnuthElement) listIter.next();
+ if (tempElement.getLayoutManager() != this) {
+ tempElement.setPosition(new NonLeafPosition(this,
+ tempElement.getPosition()));
+ }
+ targetList.add(tempElement);
+ }
+ returnList.addAll(targetList);
+ } else if (seq.isInlineSequence() && alignment == EN_JUSTIFY) {
/* justified vertical alignment (not in the XSL FO recommendation):
create a multi-layout sequence whose elements will contain
a conventional Position */
@@ -975,17 +1118,28 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// create a list of the FootnoteBodyLM handling footnotes
// whose citations are in this line
LinkedList footnoteList = new LinkedList();
- ListIterator elementIterator = ((Paragraph) knuthParagraphs.get(p)).listIterator(startIndex);
+ ListIterator elementIterator = seq.listIterator(startIndex);
while (elementIterator.nextIndex() <= endIndex) {
KnuthElement element = (KnuthElement) elementIterator.next();
if (element instanceof KnuthInlineBox
&& ((KnuthInlineBox) element).isAnchor()) {
footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
+ } else if (element instanceof KnuthBlockBox) {
+ footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
}
}
startIndex = endIndex + 1;
- returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
- footnoteList, lineLayouts.getChosenPosition(i), false));
+ LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
+ returnList.add(new KnuthBlockBox(lbp.lineHeight, footnoteList, lbp, false));
+ /* // add stretch and shrink to the returnlist
+ if (!seq.isInlineSequence()
+ && lbp.availableStretch != 0 || lbp.availableShrink != 0) {
+ returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+ false, new Position(this), false));
+ returnList.add(new KnuthGlue(0, lbp.availableStretch, lbp.availableShrink,
+ new Position(this), false));
+ }
+ */
}
}
}
@@ -1403,7 +1557,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
while (parentIter.hasNext()) {
Position pos = (Position) parentIter.next();
if (pos instanceof LineBreakPosition) {
- ListIterator paragraphIterator = null;
+ ListIterator seqIterator = null;
KnuthElement tempElement = null;
// the TLM which created the last KnuthElement in this line
LayoutManager lastLM = null;
@@ -1412,6 +1566,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
LineArea lineArea = new LineArea();
lineArea.setStartIndent(lbp.startIndent);
lineArea.setBPD(lbp.lineHeight);
+ lineArea.setIPD(lbp.lineWidth);
lc.setBaseline(lbp.baseline);
lc.setLineHeight(lbp.lineHeight);
lc.setMiddleShift(middleShift);
@@ -1419,43 +1574,46 @@ public class LineLayoutManager extends InlineStackingLayoutManager
lc.setBottomShift(lbp.bottomShift);
iCurrParIndex = lbp.iParIndex;
- Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex);
+ KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex);
iEndElement = lbp.getLeafPos();
- // ignore the first elements added by the LineLayoutManager
- iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-
- // ignore the last elements added by the LineLayoutManager
- iEndElement -= (iEndElement == (currPar.size() - 1))
+ if (seq instanceof Paragraph) {
+ Paragraph currPar = (Paragraph) seq;
+ // ignore the first elements added by the LineLayoutManager
+ iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
+
+ // ignore the last elements added by the LineLayoutManager
+ iEndElement -= (iEndElement == (currPar.size() - 1))
? currPar.ignoreAtEnd : 0;
-
+ }
+
// ignore the last element in the line if it is a KnuthGlue object
- paragraphIterator = currPar.listIterator(iEndElement);
- tempElement = (KnuthElement) paragraphIterator.next();
+ seqIterator = seq.listIterator(iEndElement);
+ tempElement = (KnuthElement) seqIterator.next();
if (tempElement.isGlue()) {
iEndElement --;
// this returns the same KnuthElement
- paragraphIterator.previous();
- tempElement = (KnuthElement) paragraphIterator.previous();
+ seqIterator.previous();
+ tempElement = (KnuthElement) seqIterator.previous();
}
lastLM = tempElement.getLayoutManager();
// ignore KnuthGlue and KnuthPenalty objects
// at the beginning of the line
- paragraphIterator = currPar.listIterator(iStartElement);
- tempElement = (KnuthElement) paragraphIterator.next();
- while (!tempElement.isBox() && paragraphIterator.hasNext()) {
- tempElement = (KnuthElement) paragraphIterator.next();
+ seqIterator = seq.listIterator(iStartElement);
+ tempElement = (KnuthElement) seqIterator.next();
+ while (!tempElement.isBox() && seqIterator.hasNext()) {
+ tempElement = (KnuthElement) seqIterator.next();
iStartElement ++;
}
// Add the inline areas to lineArea
PositionIterator inlinePosIter
- = new KnuthPossPosIter(currPar, iStartElement,
+ = new KnuthPossPosIter(seq, iStartElement,
iEndElement + 1);
iStartElement = lbp.getLeafPos() + 1;
- if (iStartElement == currPar.size()) {
+ if (iStartElement == seq.size()) {
// advance to next paragraph
iStartElement = 0;
}
@@ -1507,11 +1665,73 @@ public class LineLayoutManager extends InlineStackingLayoutManager
lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
}
parentLM.addChildArea(lineArea);
+ } else if (pos instanceof NonLeafPosition) {
+ // Nested block-level content;
+ // go down the LM stack again;
+ // collect all consecutive NonLeafPosition objects,
+ // "unwrap" them and put the child positions in a new list.
+ LinkedList positionList = new LinkedList();
+ Position innerPosition;
+ innerPosition = ((NonLeafPosition) pos).getPosition();
+ positionList.add(innerPosition);
+ while (parentIter.hasNext()) {
+ pos = (Position)parentIter.peekNext();
+ if (!(pos instanceof NonLeafPosition)) {
+ break;
+ }
+ pos = (Position) parentIter.next();
+ innerPosition = ((NonLeafPosition) pos).getPosition();
+ positionList.add(innerPosition);
+ }
+
+ // do we have the last LM?
+ LayoutManager lastLM = null;
+ if (!parentIter.hasNext()) {
+ lastLM = innerPosition.getLM();
+ }
+
+ // this may be wrong; not all areas belong inside a single line area
+ // see InlineStackingLM.addChildArea
+ LineArea lineArea = new LineArea();
+ setCurrentArea(lineArea);
+ setChildContext(lc);
+
+ PositionIterator childPosIter = new StackingIter(positionList.listIterator());
+ LayoutContext blocklc = new LayoutContext(0);
+ blocklc.setLeadingSpace(new SpaceSpecifier(true));
+ blocklc.setTrailingSpace(new SpaceSpecifier(false));
+ blocklc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+ while ((childLM = childPosIter.getNextChildLM()) != null) {
+ // set last area flag
+ blocklc.setFlags(LayoutContext.LAST_AREA,
+ (context.isLastArea() && childLM == lastLM));
+ blocklc.setStackLimit(context.getStackLimit());
+ // Add the line areas to Area
+ childLM.addAreas(childPosIter, blocklc);
+ blocklc.setLeadingSpace(blocklc.getTrailingSpace());
+ blocklc.setTrailingSpace(new SpaceSpecifier(false));
+ }
+ lineArea.updateExtentsFromChildren();
+ parentLM.addChildArea(lineArea);
} else {
// pos was the Position inside a penalty item, nothing to do
}
}
setCurrentArea(null); // ?? necessary
}
+
+ public void addChildArea(Area childArea) {
+ // Make sure childArea is inline area
+ if (childArea instanceof InlineArea) {
+ Area parent = getCurrentArea();
+ if (getContext().resolveLeadingSpace()) {
+ addSpace(parent,
+ getContext().getLeadingSpace().resolve(false),
+ getContext().getSpaceAdjust());
+ }
+ parent.addChildArea(childArea);
+ }
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
index 1a33d196c..77d560df1 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
@@ -26,6 +26,7 @@ import java.util.ListIterator;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.KnuthSequence;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthGlue;
@@ -418,6 +419,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
public LinkedList getNextKnuthElements(LayoutContext context,
int alignment) {
LinkedList returnList = new LinkedList();
+ KnuthSequence sequence = new KnuthSequence(true);
+ returnList.add(sequence);
while (iNextStart < textArray.length) {
if (textArray[iNextStart] == SPACE
@@ -425,7 +428,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// normal, breaking space
// or non-breaking space
if (textArray[iNextStart] == NBSPACE) {
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, vecAreaInfo.size() - 1),
false));
@@ -436,23 +439,23 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
- 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthInlineBox(0, 0, 0, 0,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
new LeafPosition(this, -1), true));
iNextStart ++;
@@ -464,13 +467,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, 0, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
- 3 * wordSpaceIPD.opt, 0,
new LeafPosition(this, -1), true));
@@ -482,7 +485,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt,
wordSpaceIPD.opt - wordSpaceIPD.min,
@@ -495,7 +498,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt, 0,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
@@ -507,10 +510,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
(new AreaInfo(iNextStart, (short) (iNextStart + 1),
(short) 1, (short) 0,
wordSpaceIPD, false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthGlue(wordSpaceIPD.opt,
wordSpaceIPD.max - wordSpaceIPD.opt,
wordSpaceIPD.opt - wordSpaceIPD.min,
@@ -518,12 +521,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
iNextStart ++;
} else if (textArray[iNextStart] == NEWLINE) {
// linefeed; this can happen when linefeed-treatment="preserve"
- // add a penalty item to the list and return
- returnList.add
+ // add a penalty item to the list and start a new sequence
+ sequence.add
(new KnuthPenalty(0, -KnuthElement.INFINITE,
false, null, false));
+ sequence = new KnuthSequence(true);
+ returnList.add(sequence);
iNextStart ++;
- return returnList;
} else {
// the beginning of a word
iThisStart = iNextStart;
@@ -548,25 +552,25 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
if (letterSpaceIPD.min == letterSpaceIPD.max) {
// constant letter space; simply return a box
// whose width includes letter spaces
- returnList.add
+ sequence.add
(new KnuthInlineBox(wordIPD.opt, lead, total, middle,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
} else {
// adjustable letter space;
// some other KnuthElements are needed
- returnList.add
+ sequence.add
(new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
lead, total, middle,
new LeafPosition(this, vecAreaInfo.size() - 1), false));
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthElement.INFINITE, false,
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
new LeafPosition(this, -1), true));
- returnList.add
+ sequence.add
(new KnuthInlineBox(0, lead, total, middle,
new LeafPosition(this, -1), true));
}
@@ -577,10 +581,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
&& iTempStart < textArray.length
&& textArray[iTempStart] != SPACE
&& textArray[iTempStart] != NBSPACE) {
- returnList.add
+ sequence.add
(new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
new LeafPosition(this, -1), false));
- returnList.add
+ sequence.add
(new KnuthGlue(letterSpaceIPD.opt,
letterSpaceIPD.max - letterSpaceIPD.opt,
letterSpaceIPD.opt - letterSpaceIPD.min,
@@ -592,6 +596,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
iNextStart = iTempStart;
}
} // end of while
+ if (((List)returnList.getLast()).size() == 0) {
+ //Remove an empty sequence because of a trailing newline
+ returnList.removeLast();
+ }
setFinished(true);
if (returnList.size() > 0) {
return returnList;
@@ -605,7 +613,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
// look at the Position stored in the first element in oldList
// which is always a box
ListIterator oldListIterator = oldList.listIterator();
- LeafPosition pos = (LeafPosition) ((KnuthBox) oldListIterator.next()).getPosition();
+ KnuthElement el = (KnuthElement)oldListIterator.next();
+ LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos());
ai.iLScount ++;
ai.ipdArea.add(letterSpaceIPD);