aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKaren Lease <klease@apache.org>2002-05-13 06:12:42 +0000
committerKaren Lease <klease@apache.org>2002-05-13 06:12:42 +0000
commiteb253d81c05132eefa53e762c403ca7236382a16 (patch)
treef63108d81354d6fef2d45292c8e551e47fbdb85c /src
parentb45cb4b5005f233e501e3ab815d362539af885e3 (diff)
downloadxmlgraphics-fop-eb253d81c05132eefa53e762c403ca7236382a16.tar.gz
xmlgraphics-fop-eb253d81c05132eefa53e762c403ca7236382a16.zip
Refactor Line and InlineStacking; correct and extend space-handling code
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194820 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r--src/org/apache/fop/layoutmgr/BreakCost.java16
-rw-r--r--src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java274
-rw-r--r--src/org/apache/fop/layoutmgr/LayoutContext.java56
-rw-r--r--src/org/apache/fop/layoutmgr/LineBPLayoutManager.java295
-rw-r--r--src/org/apache/fop/layoutmgr/TextBPLayoutManager.java9
5 files changed, 423 insertions, 227 deletions
diff --git a/src/org/apache/fop/layoutmgr/BreakCost.java b/src/org/apache/fop/layoutmgr/BreakCost.java
index 98b05e19f..42a695ed1 100644
--- a/src/org/apache/fop/layoutmgr/BreakCost.java
+++ b/src/org/apache/fop/layoutmgr/BreakCost.java
@@ -15,6 +15,7 @@ import org.apache.fop.area.Area;
*/
public class BreakCost {
private Area breakArea;
+ private BreakPoss bp;
private int cost; // Will be more complicated than this!
@@ -23,8 +24,21 @@ public class BreakCost {
this.cost = cost;
}
+ public BreakCost(BreakPoss bp, int cost) {
+ this.bp = bp;
+ this.cost = cost;
+ }
+
+ BreakPoss getBP() {
+ return this.bp;
+ }
+
Area getArea() {
- return breakArea;
+ return this.breakArea;
+ }
+
+ int getCost() {
+ return this.cost;
}
public BreakCost chooseLowest(BreakCost otherCost) {
diff --git a/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
index be87055c4..2a1763ea3 100644
--- a/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java
@@ -18,6 +18,7 @@ import org.apache.fop.area.inline.InlineParent;
import java.util.Iterator;
import java.util.ListIterator;
+import java.util.HashMap;
/**
* LayoutManager for objects which stack children in the inline direction,
@@ -58,12 +59,6 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
/**
- * Holds IPD of all areas which would be generated by previously
- * complete childLM since last area was generated.
- */
- private MinOptMax m_prevContentIPD = new MinOptMax(0);
-
- /**
* Size of any start or end borders and padding.
*/
private MinOptMax m_allocIPD = new MinOptMax(0);
@@ -73,23 +68,20 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
*/
private MinOptMax m_extraBPD;
- /** Holds IPD of a child BP which had no break-after flag. We don't
- * add this to m_previousIPD until we are sure that the next break
- * position can really fit.
- */
- private MinOptMax m_pendingIPD = new MinOptMax(0);
private InlineProps m_inlineProps = null;
private BorderAndPadding m_borderProps = null;
private InlineParent m_inlineArea;
- private boolean m_bFirstArea;
private BreakPoss m_prevBP;
+ private LayoutContext m_childLC ;
+
+ /** Used to store previous content IPD for each child LM. */
+ private HashMap m_hmPrevIPD = new HashMap();
public InlineStackingBPLayoutManager(FObj fobj, ListIterator childLMiter) {
super(fobj, childLMiter);
- m_bFirstArea = true;
// Initialize inline properties (borders, padding, space)
// initProperties();
}
@@ -119,13 +111,13 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
return new MinOptMax(iBP);
}
- private boolean hasLeadingFence(boolean bNotFirst) {
+ protected boolean hasLeadingFence(boolean bNotFirst) {
int iBP = m_borderProps.getPadding(BorderAndPadding.START, bNotFirst);
iBP += m_borderProps.getBorderWidth(BorderAndPadding.START, bNotFirst);
return (iBP > 0);
}
- private boolean hasTrailingFence(boolean bNotLast) {
+ protected boolean hasTrailingFence(boolean bNotLast) {
int iBP = m_borderProps.getPadding(BorderAndPadding.END, bNotLast);
iBP += m_borderProps.getBorderWidth(BorderAndPadding.END, bNotLast);
return (iBP > 0);
@@ -139,13 +131,21 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
if (wrappedPos != null) {
// Back up the layout manager iterator
reset(wrappedPos.m_childLM, wrappedPos.m_childPosition);
+ if (m_prevBP != null &&
+ m_prevBP.getLayoutManager() !=wrappedPos.m_childLM) {
+ m_childLC = null;
+ }
+ m_prevBP = new BreakPoss(wrappedPos.m_childLM,
+ wrappedPos.m_childPosition);
}
else {
- // Backup to first child layout manager
+ // Backup to start of first child layout manager
System.err.println("InlineStackingBPLM: resetPosition(null)");
+ m_prevBP = null;
super.resetPosition(prevPos);
}
// Do we need to reset some context like pending or prevContent?
+ // What about m_prevBP?
}
@@ -168,99 +168,119 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
else return false; // ??? NO child LM?
}
+ protected MinOptMax getPrevIPD(LayoutManager lm) {
+ return (MinOptMax)m_hmPrevIPD.get(lm);
+ }
+
+ protected void clearPrevIPD() {
+ m_hmPrevIPD.clear();
+ }
+
public BreakPoss getNextBreakPoss(LayoutContext lc,
BreakPoss.Position pbp) {
// Get a break from currently active child LM
BreakPoss bp =null;
BPLayoutManager curLM ;
- // Handle space before
- boolean bIncludeStartSpace=false;
- LayoutContext childLC = new LayoutContext(lc);
- if (lc.isStart()) {
- // First call to this LM in new parent "area", ie, this may
+ SpaceSpecifier leadingSpace = lc.getPendingSpace();
+
+ if (lc.startsNewArea()) {
+ // First call to this LM in new parent "area", but this may
// not be the first area created by this inline
+ m_childLC = new LayoutContext(lc);
lc.getPendingSpace().addSpace(m_inlineProps.spaceStart);
// Check for "fence"
- if (hasLeadingFence(!m_bFirstArea)) {
- bIncludeStartSpace=true;
+ if (hasLeadingFence(!lc.isFirstArea())) {
// Reset leading space sequence for child areas
- childLC.setPendingSpace(new SpaceSpecifier(false));
+ leadingSpace = new SpaceSpecifier(false);
}
// Reset state variables
- m_pendingIPD = new MinOptMax(0);
- m_prevContentIPD = new MinOptMax(0);
+ clearPrevIPD(); // Clear stored prev content dimensions
}
- else {
- // Handle pending IPD: if we are called again, we assume previous
- // break was OK
- m_prevContentIPD.add(m_pendingIPD);
- m_pendingIPD = new MinOptMax(0);
- }
-// if (m_prevChildLM != curLM && m_prevChildLM != null) {
-// // Change child LM
-// m_prevContentIPD.add(m_pendingIPD);
-// }
+ // We only do this loop more than once if a childLM returns
+ // a null BreakPoss, meaning it has nothing (more) to layout.
while ((curLM = getChildLM()) != null) {
- // ????
- /* If first break for this child, set START_AREA flag */
- if (m_prevBP == null || m_prevBP.getLayoutManager()!=curLM) {
- childLC.setFlags(LayoutContext.START_AREA);
- if (m_prevBP != null) {
- childLC.setPendingSpace(m_prevBP.getTrailingSpace());
- }
- }
+ /* If first break for this child LM, set START_AREA flag
+ * and initialize pending space from previous LM sibling's
+ * trailing space specifiers.
+ */
+ boolean bFirstChildBP = (m_prevBP == null ||
+ m_prevBP.getLayoutManager()!=curLM);
+
+ initChildLC(m_childLC, m_prevBP, lc.startsNewArea(), bFirstChildBP,
+ leadingSpace);
- if (((bp = curLM.getNextBreakPoss(childLC)) != null)) {
- // && couldEndLine(bp)) {
+ if (((bp = curLM.getNextBreakPoss(m_childLC)) != null)) {
break;
}
-// if (bp.isLastArea()) {
-// // NORMALLY IT MUST BE!
-// m_pendingIPD.add(bp.getStackingSize());
-// m_prevBP = bp;
-// }
+ // If LM has no content, should it generate any area? If not,
+ // should trailing space from a previous area interact with
+ // leading space from a following area?
}
if (bp==null) {
setFinished(true);
- return null; // There was no childLM
+ return null; // There was no childLM with anything to layout
// Alternative is to return a BP with the isLast flag set
}
else {
- // TODO! need to know whether this BP is in the first area for FO!
- return makeBreakPoss(bp, lc.isStart(),
- (getChildLM() == null), lc);
+ return makeBreakPoss(bp, lc, (getChildLM() == null));
}
}
- protected boolean couldEndLine(BreakPoss bp) {
- if (bp.canBreakAfter()) {
- return true; // no keep, ends on break char
+ /** ATTENTION: ALSO USED BY LineBPLayoutManager! */
+ protected void initChildLC(LayoutContext childLC, BreakPoss prevBP,
+ boolean bStartParent, boolean bFirstChildBP,
+ SpaceSpecifier leadingSpace) {
+
+ childLC.setFlags(LayoutContext.NEW_AREA,
+ (bFirstChildBP || bStartParent));
+ if (bStartParent) {
+ // Start of a new line area or inline parent area
+ childLC.setFlags(LayoutContext.FIRST_AREA, bFirstChildBP );
+ childLC.setPendingSpace(leadingSpace);
}
- else if (bp.isSuppressible()) {
- // NOTE: except at end of content for this LM!!
- // Never break after only space chars or any other sequence
- // of areas which would be suppressed at the end of the line.
- return false;
+ else if (bFirstChildBP) {
+ // Space-after sequence from previous "area"
+ childLC.setFlags(LayoutContext.FIRST_AREA, true);
+ childLC.setPendingSpace(prevBP.getTrailingSpace());
}
else {
- // See if could break before next area
- LayoutContext lc=new LayoutContext();
- BPLayoutManager nextLM = getChildLM();
- return (nextLM == null ||
- nextLM.canBreakBefore(lc));
+ childLC.setPendingSpace(null);
}
+
}
+// protected boolean couldEndLine(BreakPoss bp) {
+// if (bp.canBreakAfter()) {
+// return true; // no keep, ends on break char
+// }
+// else if (bp.isSuppressible()) {
+// // NOTE: except at end of content for this LM!!
+// // Never break after only space chars or any other sequence
+// // of areas which would be suppressed at the end of the line.
+// return false;
+// }
+// else {
+// // See if could break before next area
+// LayoutContext lc=new LayoutContext();
+// BPLayoutManager nextLM = getChildLM();
+// return (nextLM == null ||
+// nextLM.canBreakBefore(lc));
+// }
+// }
- protected BreakPoss makeBreakPoss(BreakPoss bp, boolean bIsFirst,
- boolean bIsLast, LayoutContext lc) {
+
+ private BreakPoss makeBreakPoss(BreakPoss bp, LayoutContext lc,
+ boolean bIsLast) {
WrappedPosition inlbp =
new WrappedPosition(bp.getLayoutManager(), bp.getPosition());
BreakPoss myBP = new BreakPoss(this, inlbp, bp.getFlags());
+ myBP.setFlag(BreakPoss.ISFIRST, lc.isFirstArea());
+ myBP.setFlag(BreakPoss.ISLAST, bIsLast);
+
// Update dimension information for our allocation area,
// including child areas
// generated by previous childLM which have completed layout
@@ -268,45 +288,105 @@ public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager {
// This includes all previous breakinfo
MinOptMax bpDim = (MinOptMax)bp.getStackingSize().clone();
+ MinOptMax prevIPD = updatePrevIPD(bp, m_prevBP,
+ lc.startsNewArea(), lc.isFirstArea());
- if (m_prevBP == null ||
- m_prevBP.getLayoutManager() != bp.getLayoutManager()) {
- /* This is first bp generated by child (in this parent area).
- * Calculate space-start on this area in combination with any
- * pending space-end on previously generated break possibilities.
- * Can also have leading space if this FO has fence-preceding.
- */
- bpDim.add(bp.resolveLeadingSpace());
- }
- if (bp.isLastArea()) {
- m_pendingIPD.add(bpDim);
- // See if our area is also done
-
- }
+ if (lc.startsNewArea()) {
+ myBP.setLeadingSpace(lc.getPendingSpace());
+ }
- // Start and end borders and padding
- bpDim.add(m_prevContentIPD);
- bpDim.add(getExtraIPD(!bIsFirst, !bIsLast));
+// if (lc.startsNewArea()) {
+// if (hasLeadingFence(!lc.isFirstArea())) {
+// // Space-start before first child area placed
+// prevIPD.add(bp.resolveLeadingSpace());
+// }
+// // Space-start sequence passed to ancestors
+// myBP.setLeadingSpace(lc.getPendingSpace());
+// m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
+// }
+// else {
+// // In case of reset to a previous position, it may already
+// // be calculated
+// prevIPD = (MinOptMax)m_hmPrevIPD.get(bp.getLayoutManager());
+// if (prevIPD == null) {
+// // ASSERT(m_prevBP.getLayoutManager() != bp.getLayoutManager());
+// /* This is first bp generated by child (in this parent area).
+// * Calculate space-start on this area in combination with any
+// * pending space-end with previous break.
+// * Corresponds to Space between two child areas.
+// */
+// prevIPD =
+// (MinOptMax)m_hmPrevIPD.get(m_prevBP.getLayoutManager());
+// prevIPD = MinOptMax.add(prevIPD, bp.resolveLeadingSpace());
+// prevIPD.add(m_prevBP.getStackingSize());
+// m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
+// }
+// }
+ // Add size of previous child areas which are finished
+ bpDim.add(prevIPD);
+// if (bp.isLastArea()) {
+// m_childLC.setPendingSpace((SpaceSpecifier)bp.getTrailingSpace().
+// clone());
+// }
+
+ SpaceSpecifier trailingSpace = bp.getTrailingSpace();
+ if (hasTrailingFence(!bIsLast)) {
+ bpDim.add(bp.resolveTrailingSpace(false));
+ trailingSpace = new SpaceSpecifier(false);
+ }
+ trailingSpace.addSpace(m_inlineProps.spaceEnd);
+ myBP.setTrailingSpace(trailingSpace);
+
+ // Add start and end borders and padding
+ bpDim.add(getExtraIPD(!lc.isFirstArea(), !bIsLast));
myBP.setStackingSize(bpDim);
myBP.setNonStackingSize(MinOptMax.add(bp.getNonStackingSize(),
m_extraBPD));
+
+ m_prevBP = bp;
if (bIsLast) {
setFinished(true); // Our last area, so indicate done
- myBP.setFlag(BreakPoss.ISLAST, true);
}
- else {
- myBP.setFlag(BreakPoss.ISLAST, false);
- }
- myBP.setTrailingSpace((SpaceSpecifier)bp.getTrailingSpace().clone());
- myBP.getTrailingSpace().addSpace(m_inlineProps.spaceEnd);
- // If this FO doesn't have fence-start, then this value should
- // come from the lower level BP!
- myBP.setLeadingSpace(new SpaceSpecifier(false));
- m_prevBP = bp;
return myBP;
}
+ /** ATTENTION: ALSO USED BY LineBPLayoutManager! */
+ protected MinOptMax updatePrevIPD(BreakPoss bp, BreakPoss prevBP,
+ boolean bStartParent, boolean bFirstArea)
+ {
+ MinOptMax prevIPD = new MinOptMax(0);
+
+ if (bStartParent) {
+ if (hasLeadingFence(!bFirstArea)) {
+ // Space-start before first child area placed
+ prevIPD.add(bp.resolveLeadingSpace());
+ }
+ // Space-start sequence passed to ancestors
+ // myBP.setLeadingSpace(lc.getPendingSpace());
+ m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
+ }
+ else {
+ // In case of reset to a previous position, it may already
+ // be calculated
+ prevIPD = (MinOptMax)m_hmPrevIPD.get(bp.getLayoutManager());
+ if (prevIPD == null) {
+ // ASSERT(prevBP.getLayoutManager() != bp.getLayoutManager());
+ /* This is first bp generated by child (in this parent area).
+ * Calculate space-start on this area in combination with any
+ * pending space-end with previous break.
+ * Corresponds to Space between two child areas.
+ */
+ prevIPD =
+ (MinOptMax)m_hmPrevIPD.get(prevBP.getLayoutManager());
+ prevIPD = MinOptMax.add(prevIPD, bp.resolveLeadingSpace());
+ prevIPD.add(prevBP.getStackingSize());
+ m_hmPrevIPD.put(bp.getLayoutManager(), prevIPD);
+ }
+ }
+ return prevIPD;
+ }
+
/******
protected BreakableText getText(BreakPoss prevBP, BreakPoss lastBP) {
diff --git a/src/org/apache/fop/layoutmgr/LayoutContext.java b/src/org/apache/fop/layoutmgr/LayoutContext.java
index bad0a871f..12e693716 100644
--- a/src/org/apache/fop/layoutmgr/LayoutContext.java
+++ b/src/org/apache/fop/layoutmgr/LayoutContext.java
@@ -17,8 +17,8 @@ public class LayoutContext {
* Values for flags.
*/
public static final int LINEBREAK_AT_LF_ONLY = 0x01;
- public static final int START_BLOCK = 0x02;
- public static final int START_AREA = 0x02; // inline too
+ /** Generated break possibility is first in a new area */
+ public static final int NEW_AREA = 0x02;
public static final int IPD_UNKNOWN = 0x04;
/** Signal to a Line LM that a higher level LM may provoke a change
* in the reference area, thus ref area IPD. The LineLM should return
@@ -33,6 +33,7 @@ public class LayoutContext {
* except the first.
*/
public static final int SUPPRESS_LEADING_SPACE = 0x10;
+ public static final int FIRST_AREA = 0x20;
public int flags; // Contains some set of flags defined above
@@ -43,13 +44,8 @@ public class LayoutContext {
* These LM <b>may</b> wish to pass this information down to lower
* level LM to allow them to optimize returned break possibilities.
*/
- MinOptMax stackLimit;
+ MinOptMax m_stackLimit;
- /** Current stacking dimension, either IPD or BPD, depending on
- * caller. This is generally the value returned by a previous call
- * to getNextBreakPoss().
- */
- MinOptMax m_stackSize;
/** True if current top-level reference area is spanning. */
boolean bIsSpan;
@@ -63,27 +59,49 @@ public class LayoutContext {
public LayoutContext(LayoutContext parentLC) {
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
- this.stackLimit = null; // Don't reference parent MinOptMax!
+ this.m_stackLimit = null; // Don't reference parent MinOptMax!
this.m_pendingSpace = parentLC.m_pendingSpace; //???
// Copy other fields as necessary. Use clone???
}
- public LayoutContext() {
- this.flags = 0;
+ public LayoutContext(int flags) {
+ this.flags = flags;
this.refIPD = 0;
- stackLimit = new MinOptMax(0);
+ m_stackLimit = new MinOptMax(0);
+ m_pendingSpace = null;
}
public void setFlags(int flags) {
- this.flags |= flags;
+ setFlags(flags, true);
+ }
+
+ public void setFlags(int flags, boolean bSet) {
+ if (bSet) {
+ this.flags |= flags;
+ }
+ else {
+ this.flags &= ~flags;
+ }
}
public void unsetFlags(int flags) {
- this.flags &= ~flags;
+ setFlags(flags, false);
}
public boolean isStart() {
- return ((this.flags & START_BLOCK) != 0);
+ return ((this.flags & NEW_AREA) != 0);
+ }
+
+ public boolean startsNewArea() {
+ return ((this.flags & NEW_AREA) != 0 && m_pendingSpace != null);
+ }
+
+ public boolean isFirstArea() {
+ return ((this.flags & FIRST_AREA) != 0);
+ }
+
+ public boolean suppressLeadingSpace() {
+ return ((this.flags & SUPPRESS_LEADING_SPACE) != 0);
}
public void setPendingSpace(SpaceSpecifier space) {
@@ -94,11 +112,11 @@ public class LayoutContext {
return m_pendingSpace;
}
- public void setStackSize(MinOptMax stackSize) {
- m_stackSize = stackSize;
+ public void setStackLimit(MinOptMax stackLimit) {
+ m_stackLimit = stackLimit;
}
- public MinOptMax getStackSize() {
- return m_stackSize ;
+ public MinOptMax getStackLimit() {
+ return m_stackLimit ;
}
}
diff --git a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
index 71339821d..ef2883b86 100644
--- a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
@@ -24,6 +24,7 @@ import org.apache.fop.area.inline.Space;
import org.apache.fop.area.inline.Character;
import java.util.ListIterator;
+import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.ArrayList;
@@ -34,7 +35,7 @@ import java.util.ArrayList;
* inline areas generated by its sub layout managers.
*/
public class LineBPLayoutManager extends
- InlineStackingBPLayoutManager {
+ InlineStackingBPLayoutManager {
/**
* Private class to store information about inline breaks.
@@ -43,9 +44,11 @@ public class LineBPLayoutManager extends
*/
private static class LineBreakPosition implements BreakPoss.Position {
int m_iPos;
+ double m_dAdjust; // Percentage to adjust (stretch or shrink)
- LineBreakPosition(int iBreakIndex) {
+ LineBreakPosition(int iBreakIndex, double dAdjust) {
m_iPos = iBreakIndex;
+ m_dAdjust = dAdjust;
}
}
@@ -55,7 +58,6 @@ public class LineBPLayoutManager extends
/** Break positions returned by inline content. */
private Vector m_vecInlineBreaks = new Vector(100);
- private SpaceSpecifier m_pendingSpace;
private BreakPoss m_prevBP = null; // Last confirmed break position
private boolean m_bJustify = false; // True if fo:block text-align=JUSTIFY
private int m_iTextIndent = 0;
@@ -63,9 +65,9 @@ public class LineBPLayoutManager extends
public LineBPLayoutManager(FObj fobj, List lms, int lh, int l, int f) {
- //super(fobj, lms, lh, l, f);
+ //super(fobj, lms.listIterator(), lh, l, f);
super(fobj, lms.listIterator());
- // initProperties();
+ init(); // Normally done when started by parent!
}
protected void initProperties(PropertyManager propMgr) {
@@ -79,7 +81,6 @@ public class LineBPLayoutManager extends
}
-
/**
* Call child layout managers to generate content as long as they
* generate inline areas. If a block-level generating LM is found,
@@ -98,105 +99,85 @@ public class LineBPLayoutManager extends
return new BreakPoss(this, null, BreakPoss.NEED_IPD);
}
- BPLayoutManager prevLM = null; // previous active LM
BPLayoutManager curLM ; // currently active LM
+ BreakPoss prevBP=null;
BreakPoss bp=null; // proposed BreakPoss
- // IPD remaining in line
- MinOptMax availIPD = context.stackLimit;
+ Vector vecPossEnd = new Vector();
- // IPD of any unbreakable finished FO content
- MinOptMax pendingIPD = null;
+ // IPD remaining in line
+ MinOptMax availIPD = context.getStackLimit();
// QUESTION: maybe LayoutContext holds the Properties which
// come from block-level?
LayoutContext inlineLC = new LayoutContext(context);
- inlineLC.setPendingSpace(new SpaceSpecifier(true));
+
+ clearPrevIPD();
while ((curLM = getChildLM()) != null) {
- // INITIALIZE FLAGS FOR CALL TO CHILD LM
- boolean bFirstBPforLM = (prevLM != curLM);
- if (bFirstBPforLM) {
- prevLM = curLM;
- inlineLC.setFlags(LayoutContext.START_AREA);
- if (bp != null) {
- inlineLC.setPendingSpace(bp.getTrailingSpace());
- }
- }
- else {
- inlineLC.unsetFlags(LayoutContext.START_AREA);
- inlineLC.setPendingSpace(null);
- }
+ // INITIALIZE LAYOUT CONTEXT FOR CALL TO CHILD LM
+ // First break for the child LM in each of its areas
+ boolean bFirstBPforLM =
+ (m_vecInlineBreaks.isEmpty() ||
+ (((BreakPoss)m_vecInlineBreaks.lastElement()).
+ getLayoutManager() != curLM));
+
+ initChildLC(inlineLC, bp, (bp==null), bFirstBPforLM,
+ new SpaceSpecifier(true));
+
+// if (bp == null) {
+// // Start of a new line area
+// inlineLC.setFlags(LayoutContext.FIRST_AREA, bFirstBPforLM );
+// inlineLC.setPendingSpace(new SpaceSpecifier(true));
+// }
+// else if (bFirstBPforLM) {
+// // Space-after sequence from previous "area"
+// inlineLC.setFlags(LayoutContext.FIRST_AREA, true);
+// inlineLC.setPendingSpace(bp.getTrailingSpace());
+// }
+// else {
+// inlineLC.setPendingSpace(null);
+// }
+
+
/* If first BP in this line but line is not first in this
- * LM and previous possible linebreak was not forced (LINEFEED),
+ * LM and previous line end decision was not forced (LINEFEED),
* then set the SUPPRESS_LEADING_SPACE flag.
*/
- if (bp == null && !m_vecInlineBreaks.isEmpty() &&
- ((BreakPoss)m_vecInlineBreaks.lastElement()).
- isForcedBreak()==false) {
- inlineLC.setFlags(LayoutContext.SUPPRESS_LEADING_SPACE);
- }
- else {
- inlineLC.unsetFlags(LayoutContext.SUPPRESS_LEADING_SPACE);
- }
+ inlineLC.setFlags(LayoutContext.SUPPRESS_LEADING_SPACE,
+ (bp == null && !m_vecInlineBreaks.isEmpty() &&
+ ((BreakPoss)m_vecInlineBreaks.lastElement()).
+ isForcedBreak()==false));
+
// GET NEXT POSSIBLE BREAK FROM CHILD LM
+ prevBP = bp;
if ((bp = curLM.getNextBreakPoss(inlineLC, null)) != null) {
+ // Add any space before and previous content dimension
+ MinOptMax prevIPD = updatePrevIPD(bp, prevBP, (prevBP==null),
+ inlineLC.isFirstArea());
+ MinOptMax bpDim = MinOptMax.add(bp.getStackingSize(), prevIPD);
+
// check if this bp fits in line
- MinOptMax bpDim = (MinOptMax)bp.getStackingSize().clone();
- /* If first BP for this LM (in this call)
- * add any leading space.
- */
- if (bFirstBPforLM) {
- if (pendingIPD != null) {
- bpDim.add(pendingIPD);
- }
- bpDim.add(bp.resolveLeadingSpace());
- }
boolean bBreakOK = couldEndLine(bp);
if (bBreakOK) {
- /* Add any non-conditional trailing space. */
+ /* Add any non-conditional trailing space, assuming we
+ * end the line here. If we can't break here, we just
+ * check if the content fits. */
bpDim.add(bp.resolveTrailingSpace(true));
}
+ // TODO: stop if linebreak is forced (NEWLINE)
+ // PROBLEM: interaction with wrap which can be set
+ // at lower levels!
+ System.err.println("BPdim=" + bpDim.opt);
+
// Check if proposed area would fit in line
- if (bpDim.max < availIPD.min) {
- // Break fits buts is short
- if (bBreakOK) {
- if (pendingIPD != null) {
- availIPD.subtract(pendingIPD);
- // Subtract space-start for this area, since
- // we know at least part of it fits.
- availIPD.subtract(bp.getLeadingSpace().
- resolve(false));
- pendingIPD = null;
- // Add all pending BP list members to BP list
- }
- m_prevBP = bp; // Save reference to this BP
- m_vecInlineBreaks.add(bp);
- // Handle end of this LM's areas
- if (bp.isLastArea()) {
- /* NOTE: this doesn't include space-end since
- * it may combine with space-start on the
- * following FO's first area.
- */
- availIPD.subtract(bp.getStackingSize());
- }
- }
- else {
- /* Can't end line here, so mark size pending.
- * This includes any previosly pending size,
- * already calculated above.
- */
- if (bp.isLastArea()) {
- pendingIPD = bpDim;
- }
- // Add BP to the list even though we can't break here
- // We need to keep it for area generation
- m_vecInlineBreaks.add(bp);
- }
- }
- else if (bpDim.min > availIPD.max) {
+ if (bpDim.min > availIPD.max) {
+ // See if we have already found a potential break
+ if (vecPossEnd.size() > 0) break;
+
// This break position doesn't fit
+ // TODO: If we are in nowrap, we use it as is!
if (m_bJustify || m_prevBP == null) {
// try to find a hyphenation point in the word
// which spans the queued breaks and the proposed bp
@@ -225,23 +206,38 @@ public class LineBPLayoutManager extends
break;
}
else {
- /* This is a possible line BP (line could be filled)
- * bpDim.max >= availIPD.min
- * Keep this as a possible break, depending on "cost".
- * We will choose lowest cost. Cost depends on stretch
- * (ie, bpDim.opt closes to availIPD.opt), keeps
- * and hyphenation.
- */
- m_prevBP = bp;
- break; //???
- }
+ // Add the BP to the list whether or not we can break
+ m_vecInlineBreaks.add(bp);
+ // Handle end of this LM's areas
+ if (bBreakOK) {
+ m_prevBP = bp; // Save reference to this BP
+ if (bp.isForcedBreak()) {
+ break;
+ }
+ if (bpDim.max >= availIPD.min) {
+ /* This is a possible line BP (line could be filled)
+ * bpDim.max >= availIPD.min
+ * Keep this as a possible break, depending on
+ * "cost". We will choose lowest cost.
+ * Cost depends on stretch
+ * (ie, bpDim.opt closes to availIPD.opt), keeps
+ * and hyphenation.
+ */
+ System.err.println("Found potential linebreak");
+ vecPossEnd.add(new BreakCost(bp,
+ Math.abs(availIPD.opt - bpDim.opt )));
+ }
+ // Otherwise it's short
+ }
+ else {
+ /* Can't end line here. */
+ }
+ } // end of bpDim.min <= availIPD.max
} // end of getNextBreakPoss!=null on current child LM
else {
- /* What if the childLM returns null?
- * No further break possibility in current sequence of
- * inline LM. Previous break or end of area will be the
- * ending for the current line.
- * Otherwise we have filled the current line.
+ /* The child LM can return a null BreakPoss if it has
+ * nothing (more) to layout. This can happen when backing
+ * up. Just try the next child LM.
*/
}
} // end of while on child LM
@@ -249,6 +245,10 @@ public class LineBPLayoutManager extends
// No more content to layout!
setFinished(true);
}
+ // Choose the best break
+ if (!bp.isForcedBreak() && vecPossEnd.size()>0) {
+ m_prevBP = getBestBP(vecPossEnd);
+ }
// Backup child LM if necessary
if (bp != m_prevBP) {
// Remove any pending breaks from the vector
@@ -257,20 +257,104 @@ public class LineBPLayoutManager extends
}
reset(m_prevBP.getLayoutManager(), m_prevBP.getPosition());
}
- return makeLineBreak(m_prevBP);
+ // Distribute space in the line
+ MinOptMax actual = MinOptMax.add(m_prevBP.getStackingSize(),
+ getPrevIPD(m_prevBP.getLayoutManager()));
+ // ATTENTION: make sure this hasn't gotten start space for next
+ // LM added onto it!
+ actual.add(m_prevBP.resolveTrailingSpace(true));
+ System.err.println("Target opt=" + availIPD.opt +
+ " bp.opt=" + actual.opt + " bp.max=" + actual.max
+ + " bm.min=" + actual.min);
+
+ // Don't justify last line in the sequence or if forced line-end
+ boolean bJustify = (m_bJustify && !m_prevBP.isForcedBreak() &&
+ !isFinished());
+ return makeLineBreak(m_prevBP, availIPD, actual, bJustify);
+ }
+
+ protected boolean couldEndLine(BreakPoss bp) {
+ if (bp.canBreakAfter()) {
+ return true; // no keep, ends on break char
+ }
+ else if (bp.isSuppressible()) {
+ // NOTE: except at end of content for this LM!!
+ // Never break after only space chars or any other sequence
+ // of areas which would be suppressed at the end of the line.
+ return false;
+ }
+ else {
+ // See if could break before next area
+ // TODO: do we need to set anything on the layout context?
+ LayoutContext lc=new LayoutContext(0);
+ BPLayoutManager nextLM = getChildLM();
+ return (nextLM == null ||
+ nextLM.canBreakBefore(lc));
+ }
}
+ private BreakPoss getBestBP(Vector vecPossEnd) {
+ if (vecPossEnd.size()==1) {
+ return ((BreakCost)vecPossEnd.elementAt(0)).getBP();
+ }
+ // Choose the best break (use a sort on cost!)
+ Iterator iter = vecPossEnd.iterator();
+ int minCost= Integer.MAX_VALUE;
+ BreakPoss bestBP = null;
+ while (iter.hasNext()) {
+ BreakCost bc = (BreakCost)iter.next();
+ if (bc.getCost() < minCost) {
+ minCost = bc.getCost();
+ bestBP = bc.getBP();
+ }
+ }
+ return bestBP;
+ }
+
+ /** Line area is always considered to act as a fence. */
+ protected boolean hasLeadingFence(boolean bNotFirst) {
+ return true;
+ }
+
+ /** Line area is always considered to act as a fence. */
+ protected boolean hasTrailingFence(boolean bNotLast) {
+ return true;
+ }
+
+
private BreakPoss findHyphenPoss(BreakPoss prevBP, BreakPoss newBP) {
+ // Get a "word" to hyphenate by getting characters from all
+ // pending break poss which are in m_vecInlineBreaks, starting
+ // with the position just AFTER prevBP.getPosition()
return null;
}
- private BreakPoss makeLineBreak(BreakPoss inlineBP) {
+ private BreakPoss makeLineBreak(BreakPoss inlineBP, MinOptMax target,
+ MinOptMax actual, boolean bJustify) {
// make a new BP
+ // Store information needed to make areas in the LineBreakPosition!
+ // Calculate stretch or shrink factor
+
+ double dAdjust=0.0;
+ if (bJustify) {
+ if (actual.opt < target.opt) {
+ // Stretch
+ dAdjust = (double)(target.opt - actual.opt)/
+ (double)(actual.max - actual.opt);
+ }
+ else {
+ // Shrink
+ dAdjust = (double)(target.opt - actual.opt)/
+ (double)( actual.opt - actual.min);
+ }
+ }
+ System.err.println("Adjustment factor=" + dAdjust);
BreakPoss curLineBP =
new BreakPoss(this,
- new LineBreakPosition(m_vecInlineBreaks.size()-1));
+ new LineBreakPosition(m_vecInlineBreaks.size()-1,
+ dAdjust));
/* FIX ME!!
* Need to calculate line height based on all inline BP info
@@ -321,10 +405,9 @@ public class LineBPLayoutManager extends
BreakPoss bp;
Vector vecBreakPoss = new Vector(20);
- LayoutContext childLC = new LayoutContext();
// Force area creation on first call
- // NOTE: normally not necessary
- childLC.flags |= LayoutContext.CHECK_REF_AREA;
+ // NOTE: normally not necessary when fully integrated!
+ LayoutContext childLC = new LayoutContext(LayoutContext.CHECK_REF_AREA);
while (!isFinished()) {
if ((bp = getNextBreakPoss(childLC, null)) != null) {
@@ -338,13 +421,13 @@ public class LineBPLayoutManager extends
parentLM.getParentArea(null);
ipd = parentLM.getContentIPD();
childLC.flags &= ~LayoutContext.CHECK_REF_AREA;
- childLC.stackLimit = new MinOptMax(ipd - m_iIndents -
- m_iTextIndent);
+ childLC.setStackLimit(new MinOptMax(ipd - m_iIndents -
+ m_iTextIndent));
}
else {
vecBreakPoss.add(bp);
// Reset stackLimit for non-first lines
- childLC.stackLimit = new MinOptMax(ipd - m_iIndents);
+ childLC.setStackLimit(new MinOptMax(ipd - m_iIndents));
}
}
}
diff --git a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
index b0c28ec17..f1bec939d 100644
--- a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
+++ b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
@@ -190,8 +190,7 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
*/
public boolean canBreakBefore(LayoutContext context) {
char c = chars[m_iNextStart];
- return ((c == NEWLINE) ||
- ((context.flags & LayoutContext.LINEBREAK_AT_LF_ONLY)==0 &&
+ return ((c == NEWLINE) || (textInfo.bWrap &&
(CharUtilities.isSpace(c) || s_breakChars.indexOf(c)>=0)));
}
@@ -245,17 +244,19 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager {
int iFlags = 0;
- if ((context.flags & LayoutContext.START_AREA)!=0) {
+ if (context.startsNewArea()) {
/* This could be first call on this LM, or the first call
* in a new (possible) LineArea.
*/
m_ipdTotal = new MinOptMax(0);
iFlags |= BreakPoss.ISFIRST;
+ // May have leading space too which can combine with a
+ // leading word-space or letter-space
}
// HANDLE SUPPRESSED LEADING SPACES
- if ((context.flags & LayoutContext.SUPPRESS_LEADING_SPACE)!=0) {
+ if (context.suppressLeadingSpace()) {
/* If any leading space characters, ignore them. */
// NOTE: Skips word-space chars only, not other white-space!
for (; m_iNextStart < chars.length &&