aboutsummaryrefslogtreecommitdiffstats
path: root/src/org/apache/fop
diff options
context:
space:
mode:
authorKaren Lease <klease@apache.org>2002-04-28 21:31:00 +0000
committerKaren Lease <klease@apache.org>2002-04-28 21:31:00 +0000
commite7182108a113301eec9213b41ead70994d2c6a75 (patch)
tree003518dc73a1a5c77441b90c64c4ef89774bf0ac /src/org/apache/fop
parent0b8f96f941357fb49da8eca12e60164b77e4db47 (diff)
downloadxmlgraphics-fop-e7182108a113301eec9213b41ead70994d2c6a75.tar.gz
xmlgraphics-fop-e7182108a113301eec9213b41ead70994d2c6a75.zip
New files for the BreakPoss(ibility) Layout Manager scheme
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194759 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/org/apache/fop')
-rw-r--r--src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java134
-rw-r--r--src/org/apache/fop/layoutmgr/BPLayoutManager.java67
-rw-r--r--src/org/apache/fop/layoutmgr/BreakPoss.java206
-rw-r--r--src/org/apache/fop/layoutmgr/BreakPossPosIter.java40
-rw-r--r--src/org/apache/fop/layoutmgr/LayoutContext.java104
-rw-r--r--src/org/apache/fop/layoutmgr/LineBPLayoutManager.java418
-rw-r--r--src/org/apache/fop/layoutmgr/PositionIterator.java90
-rw-r--r--src/org/apache/fop/layoutmgr/TextBPLayoutManager.java412
8 files changed, 1471 insertions, 0 deletions
diff --git a/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java
new file mode 100644
index 000000000..9a0218f74
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java
@@ -0,0 +1,134 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.PropertyManager;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.area.Area;
+
+import java.util.ListIterator;
+import java.util.ArrayList;
+
+/**
+ * The base class for all BPLayoutManagers.
+ */
+public abstract class AbstractBPLayoutManager extends AbstractLayoutManager
+ implements BPLayoutManager {
+
+
+ /** True if this LayoutManager has handled all of its content. */
+ private boolean m_bFinished = false;
+
+
+ public AbstractBPLayoutManager(FObj fobj) {
+ super(fobj);
+ }
+
+
+ /**
+ * This method provides a hook for a LayoutManager to intialize traits
+ * for the areas it will create, based on Properties set on its FO.
+ */
+ protected final void initProperties() {
+ if (fobj != null) {
+ initProperties(fobj.getPropertyManager());
+ }
+ }
+
+
+ /**
+ * This method provides a hook for a LayoutManager to intialize traits
+ * for the areas it will create, based on Properties set on its FO.
+ */
+ protected void initProperties(PropertyManager pm) {
+ System.err.println("AbstractBPLayoutManager.initProperties");
+ }
+
+
+ /**
+ * Tell whether this LayoutManager has handled all of its content.
+ * @return True if there are no more break possibilities,
+ * ie. the last one returned represents the end of the content.
+ */
+ public boolean isFinished() {
+ return m_bFinished;
+ }
+
+ public void setFinished(boolean bFinished) {
+ m_bFinished = bFinished;
+ }
+
+
+// /**
+// * Get the BreakPoss at the start of the next "area".
+// * @param lc The LayoutContext for this LayoutManager.
+// * @param bpPrevEnd The Position returned by the previous call
+// * to getNextBreakPoss, or null if none.
+// */
+// public BreakPoss getStartBreakPoss(LayoutContext lc,
+// BreakPoss.Position bpPrevEnd) {
+// return null;
+// }
+
+
+ /**
+ * Generate and return the next break possibility.
+ * Each layout manager must implement this.
+ * TODO: should this be abstract or is there some reasonable
+ * default implementation?
+ */
+ public BreakPoss getNextBreakPoss(LayoutContext context) {
+ return getNextBreakPoss(context, null);
+ }
+
+
+ public BreakPoss getNextBreakPoss(LayoutContext context,
+ BreakPoss.Position prevBreakPoss) {
+ return null;
+ }
+
+ /**
+ * Return value indicating whether the next area to be generated could
+ * start a new line or flow area.
+ * In general, if can't break at the current level, delegate to
+ * the first child LM.
+ * NOTE: should only be called if the START_AREA flag is set in context,
+ * since the previous sibling LM must have returned a BreakPoss which
+ * does not allow break-after.
+ * QUESTION: in block-stacked areas, does this mean some kind of keep
+ * condition, or is it only used for inline-stacked areas?
+ * Default implementation always returns true.
+ */
+ public boolean canBreakBefore(LayoutContext context) {
+ return true;
+ }
+
+
+ public void addAreas(PositionIterator parentIter) {
+ }
+
+ /* ---------------------------------------------------------
+ * PROVIDE NULL IMPLEMENTATIONS OF METHODS from LayoutManager
+ * interface which are declared abstract in AbstractLayoutManager.
+ * ---------------------------------------------------------*/
+ public Area getParentArea(Area childArea) {
+ return null;
+ }
+
+ protected boolean flush() {
+ return false;
+ }
+
+
+
+ public boolean addChild(Area childArea) {
+ return false;
+ }
+}
+
diff --git a/src/org/apache/fop/layoutmgr/BPLayoutManager.java b/src/org/apache/fop/layoutmgr/BPLayoutManager.java
new file mode 100644
index 000000000..34bb5b126
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/BPLayoutManager.java
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+
+import org.apache.fop.area.Area;
+
+/**
+ * The interface for all BreakPoss LayoutManagers.
+ */
+public interface BPLayoutManager extends LayoutManager {
+
+ /**
+ * Return true if the next area which would be generated by this
+ * LayoutManager could start a new line (or flow for block-level FO).
+ */
+ public boolean canBreakBefore(LayoutContext lc);
+
+ /**
+ * Generate and return the next break possibility.
+ * @param context The layout context contains information about pending
+ * space specifiers from ancestor areas or previous areas, reference
+ * area inline-progression-dimension and various other layout-related
+ * information.
+ * @param prevBreakPosition If not null, gives a Position returned by
+ * this layout manager on a previous call to getNextBreakPoss. It may not
+ * be the previous one returned. The Layout Manager should return the next
+ * potential Break Possibility after prevBreakPosition.
+ * If prevBreakPosition is null, it should return the first possible
+ * BreakPoss.
+ */
+ public BreakPoss getNextBreakPoss(LayoutContext context,
+ BreakPoss.Position prevBreakPosition);
+
+ public BreakPoss getNextBreakPoss(LayoutContext context);
+
+ /** CURRENTLY NOT USED
+ public BreakPoss getStartBreakPoss(LayoutContext lc,
+ BreakPoss.Position bpPrevEnd);
+ **/
+
+ /**
+ * Return a value indicating whether this LayoutManager has laid out
+ * all its content (or generated BreakPossibilities for all content.)
+ */
+ public boolean isFinished() ;
+
+ /**
+ * Set a flag indicating whether the LayoutManager has laid out all
+ * its content. This is generally called by the LM itself, but can
+ * be called by a parentLM when backtracking.
+ */
+ public void setFinished(boolean isFinished) ;
+
+ /**
+ * Tell the layout manager to add all the child areas implied
+ * by BreakPoss.Position objectw which will be returned by the
+ * Iterator.
+ */
+ public void addAreas(PositionIterator posIter) ;
+
+}
diff --git a/src/org/apache/fop/layoutmgr/BreakPoss.java b/src/org/apache/fop/layoutmgr/BreakPoss.java
new file mode 100644
index 000000000..eb4ad4200
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/BreakPoss.java
@@ -0,0 +1,206 @@
+/*
+ * $Id$
+ * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+package org.apache.fop.layoutmgr;
+
+import org.apache.fop.area.MinOptMax;
+import org.apache.fop.traits.LayoutProps;
+
+/**
+ * Represents a break possibility for the layout manager.
+ * Used to pass information between different levels of layout manager concerning
+ * the break positions. In an inline context, before and after are interpreted as
+ * start and end.
+ * The m_position field is opaque but should represent meaningful information to
+ * the layout manager stored in m_lm.
+ * @author Karen Lease
+ */
+public class BreakPoss {
+
+ /**
+ * Marker interface. Generally a LayoutManager class will include
+ * a class implementing this interface which it uses to store its
+ * own Break Position information.
+ */
+ public interface Position {
+ }
+
+
+ /** Values for m_flags returned from lower level LM. */
+ public static final int CAN_BREAK_AFTER= 0x01; // May break after
+ public static final int ISLAST= 0x02; // Last area generated by FO
+ public static final int ISFIRST= 0x04; // First area generated by FO
+ public static final int FORCE= 0x08; // Forced break (ie LF)
+ public static final int CAN_BREAK_BEFORE=0x10;
+ public static final int NEED_IPD = 0x20;
+ public static final int HAS_ANCHORS = 0x40;
+ // Set this flag if all fo:character generated Areas would
+ // suppressed at the end or beginning of a line
+ public static final int ALL_ARE_SUPPRESS_AT_LB = 0x80;
+
+
+ /** The top-level layout manager which generated this BreakPoss. */
+ private BPLayoutManager m_lm;
+
+ /** The opaque position object used by m_lm to record its
+ * break position.
+ */
+ private Position m_position;
+
+ /**
+ * The size range in the stacking direction of the area which would be
+ * generated if this BreakPoss were used.
+ */
+ private MinOptMax m_stackSize;
+
+ /**
+ * Max height above and below the baseline. These are cumulative.
+ */
+ private int m_iMaxAscender;
+ private int m_iMaxDescender;
+
+ /** Size in the non-stacking direction (perpendicular). */
+ private MinOptMax m_nonStackSize;
+
+ private long m_flags = 0;
+ private LayoutProps m_layoutProps = new LayoutProps();
+ /**
+ private boolean m_bIsFirst=false;
+ private boolean m_bIsLast=false;
+ private boolean m_bCanBreakAfter;
+ private boolean m_bCanBreakBefore;
+ **/
+
+ /** Store space-after (or end) and space-before (or start) to be
+ * added if this break position is used.
+ */
+ private SpaceSpecifier m_spaceSpecTrailing;
+ private SpaceSpecifier m_spaceSpecLeading;
+
+ public BreakPoss(BPLayoutManager lm, Position position) {
+ this(lm,position,0);
+ }
+
+ public BreakPoss(BPLayoutManager lm, Position position, int flags) {
+ m_lm = lm;
+ m_position = position;
+ m_flags = flags;
+ }
+
+ /**
+ * The top-level layout manager responsible for this break
+ */
+ public BPLayoutManager getLayoutManager() {
+ return m_lm;
+ }
+
+ public void setLayoutManager(BPLayoutManager lm) {
+ m_lm = lm;
+ }
+
+ /**
+ * An object representing the break position in this layout manager.
+ */
+ public Position getPosition() {
+ return m_position;
+ }
+
+ public void setPosition(Position pos) {
+ m_position = pos;
+ }
+
+ public void setStackingSize(MinOptMax size) {
+ this.m_stackSize = size;
+ }
+
+ public MinOptMax getStackingSize() {
+ return this.m_stackSize ;
+ }
+
+ public void setNonStackingSize(MinOptMax size) {
+ this.m_nonStackSize = size;
+ }
+
+ public MinOptMax getNonStackingSize() {
+ return this.m_nonStackSize ;
+ }
+
+ public void setFlag(int flagBit) {
+ setFlag(flagBit, true);
+ }
+
+ public void setFlag(int flagBit, boolean bSet) {
+ if (bSet) {
+ m_flags |= flagBit;
+ }
+ else {
+ m_flags &= ~flagBit;
+ }
+ }
+
+ public boolean isLastArea() {
+ return ((m_flags & ISLAST) != 0);
+ }
+
+ public boolean isFirstArea() {
+ return ((m_flags & ISFIRST) != 0);
+ }
+
+ public boolean canBreakAfter() {
+ return ((m_flags & CAN_BREAK_AFTER) != 0);
+ }
+
+ public boolean canBreakBefore() {
+ return ((m_flags & CAN_BREAK_BEFORE) != 0);
+ }
+
+ public boolean isForcedBreak() {
+ return ((m_flags & FORCE) != 0);
+ }
+
+ public boolean isSuppressible() {
+ return ((m_flags & ALL_ARE_SUPPRESS_AT_LB) != 0);
+ }
+
+ public SpaceSpecifier getLeadingSpace() {
+ return m_spaceSpecLeading;
+ }
+
+ public MinOptMax resolveLeadingSpace() {
+ if (m_spaceSpecLeading != null) {
+ return m_spaceSpecLeading.resolve(false);
+ }
+ else return new MinOptMax(0);
+ }
+
+ public SpaceSpecifier getTrailingSpace() {
+ return m_spaceSpecTrailing;
+ }
+
+ public MinOptMax resolveTrailingSpace(boolean bEndsRefArea) {
+ if (m_spaceSpecTrailing != null) {
+ return m_spaceSpecTrailing.resolve(bEndsRefArea);
+ }
+ else return new MinOptMax(0);
+ }
+
+
+ public void setLeadingSpace(SpaceSpecifier spaceSpecLeading) {
+ m_spaceSpecLeading = spaceSpecLeading;
+ }
+
+ public void setTrailingSpace(SpaceSpecifier spaceSpecTrailing) {
+ m_spaceSpecTrailing = spaceSpecTrailing;
+ }
+
+ public LayoutProps getLayoutProps() {
+ return m_layoutProps;
+ }
+
+ public boolean checkIPD() {
+ return ((m_flags & NEED_IPD) != 0);
+ }
+}
diff --git a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java
new file mode 100644
index 000000000..0188b2731
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+
+import java.util.List;
+
+public class BreakPossPosIter extends PositionIterator {
+ private int m_iterCount ;
+
+ BreakPossPosIter(List bpList, int startPos, int endPos) {
+ super(bpList.listIterator(startPos));
+ m_iterCount = endPos - startPos;
+ }
+
+ // Check position < endPos
+
+ protected boolean checkNext() {
+ return (m_iterCount > 0 && super.checkNext());
+ }
+
+ public Object next() {
+ --m_iterCount;
+ return super.next();
+ }
+
+ protected BPLayoutManager getLM(Object nextObj) {
+ return ((BreakPoss)nextObj).getLayoutManager();
+ }
+
+ protected BreakPoss.Position getPos(Object nextObj) {
+ return ((BreakPoss)nextObj).getPosition();
+ }
+
+}
diff --git a/src/org/apache/fop/layoutmgr/LayoutContext.java b/src/org/apache/fop/layoutmgr/LayoutContext.java
new file mode 100644
index 000000000..bad0a871f
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/LayoutContext.java
@@ -0,0 +1,104 @@
+/*
+ * $Id$
+ * Copyright (C) 2002 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+package org.apache.fop.layoutmgr;
+
+import org.apache.fop.area.MinOptMax;
+
+/**
+ * This class is used to pass information to the getNextBreakPoss()
+ * method. It is set up by higher level LM and used by lower level LM.
+ */
+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
+ 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
+ * without looking for a line break.
+ */
+ public static final int CHECK_REF_AREA = 0x08;
+
+ /**
+ * If this flag is set, it indicates that any leading fo:character
+ * objects with suppress-at-line-break="suppress" should not generate
+ * areas. This is the case at the beginning of each new LineArea
+ * except the first.
+ */
+ public static final int SUPPRESS_LEADING_SPACE = 0x10;
+
+
+ public int flags; // Contains some set of flags defined above
+ /**
+ * Total available stacking dimension for a "galley-level" layout
+ * manager (Line or Flow). It is passed by the parent LM. For LineLM,
+ * the block LM determines this based on indent properties.
+ * 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;
+
+ /** 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;
+
+ /** inline-progression-dimension of nearest ancestor reference area */
+ int refIPD;
+
+ /** Current pending space-after or space-end from preceding area */
+ SpaceSpecifier m_pendingSpace;
+
+ public LayoutContext(LayoutContext parentLC) {
+ this.flags = parentLC.flags;
+ this.refIPD = parentLC.refIPD;
+ this.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;
+ this.refIPD = 0;
+ stackLimit = new MinOptMax(0);
+ }
+
+ public void setFlags(int flags) {
+ this.flags |= flags;
+ }
+
+ public void unsetFlags(int flags) {
+ this.flags &= ~flags;
+ }
+
+ public boolean isStart() {
+ return ((this.flags & START_BLOCK) != 0);
+ }
+
+ public void setPendingSpace(SpaceSpecifier space) {
+ m_pendingSpace = space;
+ }
+
+ public SpaceSpecifier getPendingSpace() {
+ return m_pendingSpace;
+ }
+
+ public void setStackSize(MinOptMax stackSize) {
+ m_stackSize = stackSize;
+ }
+
+ public MinOptMax getStackSize() {
+ return m_stackSize ;
+ }
+}
diff --git a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
new file mode 100644
index 000000000..86417d024
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java
@@ -0,0 +1,418 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.TextInfo;
+import org.apache.fop.fo.PropertyManager;
+import org.apache.fop.layout.MarginProps;
+import org.apache.fop.traits.BlockProps;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.LineArea;
+import org.apache.fop.area.MinOptMax;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.fo.properties.TextAlign;
+
+import org.apache.fop.area.inline.Word;
+import org.apache.fop.area.inline.Space;
+import org.apache.fop.area.inline.Character;
+
+import java.util.ListIterator;
+import java.util.List;
+import java.util.Vector;
+import java.util.ArrayList;
+
+
+/**
+ * BPLayoutManager for lines. It builds one or more lines containing
+ * inline areas generated by its sub layout managers.
+ */
+public class LineBPLayoutManager extends LineLayoutManager {
+
+ /**
+ * Private class to store information about inline breaks.
+ * Each value holds the start and end indexes into a List of
+ * inline break positions.
+ */
+ private static class LineBreakPosition implements BreakPoss.Position {
+ int m_iPos;
+
+ LineBreakPosition(int iBreakIndex) {
+ m_iPos = iBreakIndex;
+ }
+ }
+
+ private BPLayoutManager m_curChildLM=null;
+ private ListIterator m_childLMiter;
+
+ private LineArea m_lineArea; // LineArea currently being filled
+
+ /** 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;
+ private int m_iIndents = 0;
+
+
+ public LineBPLayoutManager(FObj fobj, List lms, int lh, int l, int f) {
+ super(fobj, lms, lh, l, f);
+ m_childLMiter = lms.listIterator();
+ initProperties();
+ }
+
+ protected void initProperties(PropertyManager propMgr) {
+ super.initProperties(propMgr);
+ System.err.println("LineBPLayoutManager.initProperties called");
+ MarginProps marginProps = propMgr.getMarginProps();
+ m_iIndents = marginProps.startIndent + marginProps.endIndent;
+ BlockProps blockProps = propMgr.getBlockProps();
+ m_bJustify = (blockProps.textAlign == TextAlign.JUSTIFY);
+ m_iTextIndent = blockProps.firstIndent;
+ }
+
+
+ /**
+ * Return next child LayoutManager or null if there is none.
+ * Note: child must implement BPLayoutManager! If it doesn't, skip it
+ * and print a warning.
+ * The list of all child layout managers is in lmList (in superclass!)
+ */
+ private BPLayoutManager getChildLM() {
+ if (m_curChildLM != null && !m_curChildLM.isFinished()) {
+ return m_curChildLM;
+ }
+ while (m_childLMiter.hasNext()) {
+ Object obj = m_childLMiter.next();
+ if (obj instanceof BPLayoutManager) {
+ m_curChildLM = (BPLayoutManager)obj;
+ m_curChildLM.setParentLM(this);
+ return m_curChildLM;
+ }
+ else {
+ m_childLMiter.remove();
+ System.err.println("WARNING: child of LineLPLayoutManager not a BPLayoutManager: " + obj.getClass().getName());
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Reset the layoutmanager "iterator" so that it will start
+ * with the passed bplm on the next call to getChildLM.
+ * @param bplm Reset iterator to this LayoutManager.
+ */
+ private void resetChildLM(BPLayoutManager bplm) {
+ if (bplm == null) return;
+ while (m_curChildLM != bplm && m_childLMiter.hasPrevious()) {
+ m_curChildLM = (BPLayoutManager)m_childLMiter.previous();
+ }
+ if ( m_curChildLM.isFinished()) {
+ m_curChildLM.setFinished(false);
+ }
+ }
+
+
+
+ /**
+ * Call child layout managers to generate content as long as they
+ * generate inline areas. If a block-level generating LM is found,
+ * finish any line being filled and return to the parent LM.
+ */
+ public BreakPoss getNextBreakPoss(LayoutContext context,
+ BreakPoss.Position prevLineBP) {
+ // Get a break from currently active child LM
+ // Set up constraints for inline level managers
+
+ if ((context.flags & LayoutContext.CHECK_REF_AREA) != 0) {
+ /* Return a BreakPoss indicating that higher level LM
+ * (page) should check reference area and possibly
+ * create a new one.
+ */
+ return new BreakPoss(this, null, BreakPoss.NEED_IPD);
+ }
+
+ BPLayoutManager prevLM = null; // previous active LM
+ BPLayoutManager curLM ; // currently active LM
+ BreakPoss bp=null; // proposed BreakPoss
+
+ // IPD remaining in line
+ MinOptMax availIPD = context.stackLimit;
+
+ // IPD of any unbreakable finished FO content
+ MinOptMax pendingIPD = null;
+
+ // QUESTION: maybe LayoutContext holds the Properties which
+ // come from block-level?
+
+ LayoutContext inlineLC = new LayoutContext(context);
+ inlineLC.setPendingSpace(new SpaceSpecifier(true));
+
+ 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);
+ }
+ /* If first BP in this line but line is not first in this
+ * LM and previous possible linebreak 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);
+ }
+ // GET NEXT POSSIBLE BREAK FROM CHILD LM
+ if ((bp = curLM.getNextBreakPoss(inlineLC,
+ (m_prevBP !=null ?
+ m_prevBP.getPosition() :
+ null))) != null) {
+ // 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. */
+ bpDim.add(bp.resolveTrailingSpace(true));
+ }
+ // 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.
+ */
+ pendingIPD = bpDim;
+ // Add BP to the pending list
+ }
+ }
+ else if (bpDim.min > availIPD.max) {
+ // This break position doesn't fit
+ if (m_bJustify || m_prevBP == null) {
+ // try to find a hyphenation point in the word
+ // which spans the queued breaks and the proposed bp
+ // Even if not justified, we must try to hyphenate if
+ // there is no breakpoint at all up to this point!
+ do {
+ bp = findHyphenPoss(m_prevBP, bp);
+ } while (bp != null &&
+ (bp.getStackingSize().min > availIPD.max));
+ if (bp == null) {
+ // Couldn't find a hyphenation point. The line
+ // will be "short".
+ }
+ else {
+ m_prevBP = bp;
+ }
+ // Handle pendingIPD if any. The hyphenation point
+ // may be within the "pending" content or after it.
+ /* Make sure child LM are updated concerning the actual
+ * hyphenation BreakPoss for their next call!
+ */
+ }
+ /* If we are not in justified text, we can end the line at
+ * prevBP.
+ */
+ 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; //???
+ }
+ } // 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.
+ */
+ }
+ } // end of while on child LM
+ if ((curLM = getChildLM())== null) {
+ // No more content to layout!
+ setFinished(true);
+ }
+ // Backup layoutmanager if necessary
+ resetChildLM(m_prevBP.getLayoutManager());
+ return makeLineBreak(m_prevBP);
+ }
+
+ /**
+ * Return whether we could end the line at the proposed Position.
+ * TODO: take keeps into account and distinguish the cost of a
+ * the break-completely forbidden or some non-0 cost.
+ * QUESTION: do we need to pass the current LineLM or childLM
+ * LayoutContext?
+ */
+ private 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));
+ }
+ }
+
+
+ private BreakPoss findHyphenPoss(BreakPoss prevBP, BreakPoss newBP) {
+ return null;
+ }
+
+ private BreakPoss makeLineBreak(BreakPoss inlineBP) {
+ // make a new BP
+ BreakPoss curLineBP =
+ new BreakPoss(this,
+ new LineBreakPosition(m_vecInlineBreaks.size()-1));
+
+ /* FIX ME!!
+ * Need to calculate line height based on all inline BP info
+ * for this line not just the current inlineBP!
+ */
+ curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
+ curLineBP.setStackingSize(inlineBP.getNonStackingSize());
+ return curLineBP;
+ }
+
+
+ // Generate and add areas to parent area
+ // Set size etc
+ public void addAreas(PositionIterator parentIter) {
+ BPLayoutManager childLM ;
+ int iStartPos = 0;
+ while (parentIter.hasNext()) {
+ LineBreakPosition lbp = (LineBreakPosition)parentIter.next();
+ System.err.println("lbp.endpos=" + lbp.m_iPos);
+ m_lineArea = new LineArea();
+ // Add the inline areas to lineArea
+ PositionIterator inlinePosIter =
+ new BreakPossPosIter(m_vecInlineBreaks,
+ iStartPos, lbp.m_iPos+1);
+ iStartPos = lbp.m_iPos+1;
+ while (inlinePosIter.hasNext() &&
+ (childLM = inlinePosIter.getNextChildLM())!= null) {
+ childLM.addAreas(inlinePosIter);
+ }
+ verticalAlign(m_lineArea);
+ parentLM.addChild(m_lineArea);
+ }
+ m_lineArea = null;
+ }
+
+ public boolean addChild(Area childArea) {
+ // Make sure childArea is inline area
+ if (childArea instanceof InlineArea) {
+ m_lineArea.addInlineArea((InlineArea)childArea);
+ }
+ return false;
+ }
+
+ // NOTE: PATCHED FOR NOW TO ADD BreakPoss stuff to Kerion's changes
+ public boolean generateAreas() {
+ // Make break positions and return lines!
+ // Set up a LayoutContext
+ int ipd = 0;
+ 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;
+
+ while (!isFinished()) {
+ if ((bp = getNextBreakPoss(childLC, null)) != null) {
+ if (bp.checkIPD()) {
+ // Need IPD in order to layout lines!
+ // This is supposed to bubble up to PageLM to
+ // make the necessary flow reference area, depending
+ // on span and break-before flags set as the BreakPoss
+ // makes its way back up the call stack.
+ // Fake it for now!
+ parentLM.getParentArea(null);
+ ipd = parentLM.getContentIPD();
+ childLC.flags &= ~LayoutContext.CHECK_REF_AREA;
+ childLC.stackLimit = new MinOptMax(ipd - m_iIndents -
+ m_iTextIndent);
+ }
+ else {
+ vecBreakPoss.add(bp);
+ // Reset stackLimit for non-first lines
+ childLC.stackLimit = new MinOptMax(ipd - m_iIndents);
+ }
+ }
+ }
+ addAreas(new BreakPossPosIter(vecBreakPoss, 0, vecBreakPoss.size()));
+ return false;
+ }
+
+
+}
+
diff --git a/src/org/apache/fop/layoutmgr/PositionIterator.java b/src/org/apache/fop/layoutmgr/PositionIterator.java
new file mode 100644
index 000000000..be8978312
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/PositionIterator.java
@@ -0,0 +1,90 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+abstract class PositionIterator implements Iterator
+{
+ Iterator m_parentIter;
+ Object m_nextObj;
+ BPLayoutManager m_childLM;
+ boolean m_bHasNext;
+
+ PositionIterator(Iterator parentIter) {
+ m_parentIter = parentIter;
+ lookAhead();
+ //checkNext();
+ }
+
+ BPLayoutManager getNextChildLM() {
+ // Move to next "segment" of iterator, ie: new childLM
+ if (m_childLM == null && m_nextObj != null) {
+ m_childLM = getLM(m_nextObj);
+ m_bHasNext = true;
+ }
+ return m_childLM;
+ }
+
+ abstract protected BPLayoutManager getLM(Object nextObj);
+
+ abstract protected BreakPoss.Position getPos(Object nextObj);
+
+ private void lookAhead() {
+ if (m_parentIter.hasNext()) {
+ m_bHasNext = true;
+ m_nextObj = m_parentIter.next();
+ }
+ else {
+ endIter();
+ }
+ }
+
+ protected boolean checkNext() {
+ BPLayoutManager lm = getLM(m_nextObj);
+ if (m_childLM==null) {
+ m_childLM = lm;
+ }
+ else if (m_childLM != lm) {
+ // End of this sub-sequence with same child LM
+ m_bHasNext = false;
+ m_childLM = null;
+ return false;
+ }
+ return true;
+ }
+
+ protected void endIter() {
+ m_bHasNext = false;
+ m_nextObj = null;
+ m_childLM = null;
+ }
+
+ public boolean hasNext() {
+ return (m_bHasNext && checkNext());
+ }
+
+
+ public Object next() throws NoSuchElementException {
+ if (m_bHasNext) {
+ Object retObj = getPos(m_nextObj);
+ lookAhead();
+ return retObj;
+ }
+ else {
+ throw new NoSuchElementException("PosIter");
+ }
+ }
+
+ public void remove() throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("PositionIterator doesn't support remove");
+ }
+}
+
diff --git a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
new file mode 100644
index 000000000..8c99cbc3b
--- /dev/null
+++ b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java
@@ -0,0 +1,412 @@
+/*
+ * $Id$
+ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
+ * For details on use and redistribution please refer to the
+ * LICENSE file included with these sources.
+ */
+
+package org.apache.fop.layoutmgr;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.TextInfo;
+import org.apache.fop.traits.SpaceVal;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.LineArea;
+import org.apache.fop.area.MinOptMax;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.Word;
+import org.apache.fop.area.inline.Space;
+import org.apache.fop.util.CharUtilities;
+import org.apache.fop.fo.properties.VerticalAlign;
+
+//import org.apache.fop.fo.properties.*;
+
+import java.util.Vector; // or use ArrayList ???
+
+/**
+ * LayoutManager for text (a sequence of characters) which generates one
+ * or more inline areas.
+ */
+public class TextBPLayoutManager extends AbstractBPLayoutManager {
+ /**
+ * Private class to store information about the break index.
+ * the field stores the index in the vector of AreaInfo which
+ * corresponds to this break position.
+ * Note: fields are directly readable in this class
+ */
+ private static class TextBreakPosition implements BreakPoss.Position {
+ short m_iAreaIndex;
+
+ TextBreakPosition(int iAreaIndex) {
+ m_iAreaIndex = (short)iAreaIndex;
+ }
+ }
+
+ /**
+ * Store information about each potential word area.
+ * Index of character which ends the area, IPD of area, including
+ * any word-space and letter-space.
+ * Number of word-spaces?
+ */
+ private class AreaInfo {
+ short m_iStartIndex;
+ short m_iBreakIndex;
+ MinOptMax m_ipdArea;
+ AreaInfo(short iStartIndex, short iBreakIndex, MinOptMax ipdArea) {
+ m_iStartIndex = iStartIndex;
+ m_iBreakIndex = iBreakIndex;
+ m_ipdArea = ipdArea;
+ }
+ }
+
+
+ // Hold all possible breaks for the text in this LM's FO.
+ private Vector m_vecAreaInfo;
+
+ /** Non-space characters on which we can end a line. */
+ static private final String s_breakChars = "-/" ;
+
+ private char[] chars;
+ private TextInfo textInfo;
+
+ private static final char NEWLINE = '\n';
+ private static final char RETURN = '\r';
+ private static final char TAB = '\t';
+ private static final char SPACE = ' ';
+ private static final char LINEBREAK = '\u2028';
+ private static final char ZERO_WIDTH_SPACE = '\u200B';
+ // byte order mark
+ private static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
+
+ /* values that prev (below) may take */
+ protected static final int NOTHING = 0;
+ protected static final int WHITESPACE = 1;
+ protected static final int TEXT = 2;
+
+ /** Start index of first character in this parent Area */
+ private short m_iAreaStart = 0;
+ /** Start index of next "word" */
+ private short m_iNextStart = 0;
+ /** Size since last makeArea call, except for last break */
+ private MinOptMax m_ipdTotal ;
+ /** Size including last break possibility returned */
+ // private MinOptMax m_nextIPD= new MinOptMax(0);
+ /** size of a space character (U+0020) glyph in current font */
+ private int m_spaceIPD;
+ /** 1/2 of word-spacing value */
+ private SpaceVal m_halfWS;
+ /** Number of space characters after previous possible break position. */
+ private int m_iNbSpacesPending;
+
+
+ public TextBPLayoutManager(FObj fobj, char[] chars,
+ TextInfo textInfo) {
+ super(fobj);
+ this.chars = chars;
+ this.textInfo = textInfo;
+ this.m_vecAreaInfo = new Vector(chars.length/5); // Guess
+
+ // With CID fonts, space isn't neccesary currentFontState.width(32)
+ m_spaceIPD = CharUtilities.getCharWidth(' ', textInfo.fs);
+ // Make half-space: <space> on either side of a word-space)
+ SpaceVal ws = textInfo.wordSpacing;
+ m_halfWS = new SpaceVal(MinOptMax.multiply(ws.space, 0.5),
+ ws.bConditional, ws.bForcing,
+ ws.iPrecedence);
+ }
+
+
+ public boolean generatesInlineAreas() {
+ return true;
+ }
+
+ /* METHODS FROM LeafNodeLayoutManager,
+ * used in Keiron's implemenation, but not here (yet at least).
+ */
+ public int size() {
+ return 0;
+ }
+
+ public InlineArea get(int index) {
+ return null;
+ }
+
+ /**
+ * Generate inline areas for words in text.
+ */
+ public boolean generateAreas() {
+ // Handle white-space characteristics. Maybe there is no area to
+ // generate....
+
+ // Iterate over characters and make text areas.
+ // Add each one to parent. Handle word-space.
+ return false;
+ }
+
+
+ // NOTE: currently not used. Remove if decide it isn't necessary!
+// /**
+// * Get the BreakPoss at the start of the next line.
+// * @param bpPrevEnd The BreakPoss at the end of the previous line
+// * or null if we should return the point at the beginning of this
+// * text run.
+// */
+// public BreakPoss getStartBreakPoss(LayoutContext lc,
+// BreakPoss.Position bpPrevEnd) {
+// BreakPoss bp = null;
+// if (bpPrevEnd == null) {
+// bp = new BreakPoss(this, new TextBreakPosition(0));
+// // Set minimum bpd (character ascent and descent)
+// // Or do this at the line level???
+// }
+// else {
+// // Skip suppressible white-space
+// // ASSERT (((TextBreakPosition)bpPrevEnd).m_iAreaIndex =
+// // m_iNextStart)
+// if ((lc.flags & LayoutContext.SUPPRESS_LEADING_SPACE)!=0) {
+// /* Skip any leading word-space characters. */
+// for (; m_iNextStart < chars.length &&
+// chars[m_iNextStart]==SPACE; m_iNextStart++);
+// }
+// // If now at end, nothing to compose here!
+// if (m_iNextStart >= chars.length) {
+// return null; // Or an "empty" BreakPoss?
+// }
+// else {
+// bp = new BreakPoss(this,
+// new TextBreakPosition(m_iNextStart));
+// }
+// }
+// return bp;
+// }
+
+
+ /**
+ * Return value indicating whether the next area to be generated could
+ * start a new line. This should only be called in the "START" condition
+ * if a previous inline BP couldn't end the line.
+ * Return true if the first character is a potential linebreak character.
+ */
+ public boolean canBreakBefore(LayoutContext context) {
+ char c = chars[m_iNextStart];
+ return ((c == NEWLINE) ||
+ ((context.flags & LayoutContext.LINEBREAK_AT_LF_ONLY)==0 &&
+ (CharUtilities.isSpace(c) || s_breakChars.indexOf(c)>=0)));
+ }
+
+ /**
+ * Return the next break possibility that fits the constraints.
+ * @param context An object specifying the flags and input information
+ * concerning the context of the BreakPoss.
+ * @para prevPos An object specifying the previous Position returned
+ * by a BreakPoss from this LM. It may be earlier than the current
+ * pointer when doing hyphenation or starting a new line.
+ * @return BreakPoss An object containing information about the next
+ * legal break position or the end of the text run if no break
+ * was found.
+ * <p>Assumptions: white-space-treatment and
+ * linefeed-treatment processing
+ * are already done, so there are no TAB or RETURN characters remaining.
+ * white-space-collapse handling is also done
+ * (but perhaps this shouldn't be true!)
+ * There may be LINEFEED characters if they weren't converted
+ * into spaces. A LINEFEED always forces a break.
+ */
+ public BreakPoss getNextBreakPoss(LayoutContext context,
+ BreakPoss.Position prevPos) {
+ /* On first call in a new Line, the START_AREA
+ * flag in LC is set.
+ */
+
+ int iFlags = 0;
+
+ if ((context.flags & LayoutContext.START_AREA)!=0) {
+ /* 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;
+ }
+
+ if (prevPos != null) {
+ TextBreakPosition tbp = (TextBreakPosition)prevPos;
+ AreaInfo ai =
+ (AreaInfo) m_vecAreaInfo.elementAt(tbp.m_iAreaIndex);
+ if (ai.m_iBreakIndex != m_iNextStart) {
+ m_iNextStart = ai.m_iBreakIndex;
+ m_vecAreaInfo.setSize(tbp.m_iAreaIndex+1);
+ System.err.println("Discarded previous text break pos");
+ }
+ }
+
+
+ // HANDLE SUPPRESSED LEADING SPACES
+ if ((context.flags & LayoutContext.SUPPRESS_LEADING_SPACE)!=0) {
+ /* If any leading space characters, ignore them. */
+ // NOTE: Skips word-space chars only, not other white-space!
+ for (; m_iNextStart < chars.length &&
+ chars[m_iNextStart]==SPACE; m_iNextStart++);
+ // If now at end, nothing to compose here!
+ if (m_iNextStart >= chars.length) {
+ return null; // Or an "empty" BreakPoss?
+ }
+ }
+
+
+ // Start of this "word", plus any non-suppressed leading space
+ // This is any kind of white-space, not just word spaces
+
+ short iThisStart = m_iNextStart;
+ MinOptMax spaceIPD = new MinOptMax(0); // Variable IPD
+ int wordIPD = 0; // Non-stretching IPD (length in base units)
+
+ // Handle inter-character spacing (word-space + letter-space)
+ // What about context.getPendingSpace() on first char in word?
+ SpaceSpecifier pendingSpace = new SpaceSpecifier(false);
+
+ for (; m_iNextStart < chars.length; m_iNextStart++) {
+ char c = chars[m_iNextStart];
+ if (CharUtilities.isAnySpace(c)==false) break;
+ if (c==SPACE) {
+ pendingSpace.addSpace(m_halfWS);
+ spaceIPD.add(pendingSpace.resolve(false));
+ wordIPD += m_spaceIPD; // Space glyph IPD
+ pendingSpace.clear();
+ pendingSpace.addSpace(m_halfWS);
+ }
+ else {
+ // If we have letter-space, so we apply this to fixed-
+ // width spaces (which are not word-space) also?
+ spaceIPD.add(pendingSpace.resolve(false));
+ pendingSpace.clear();
+ wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
+ }
+ }
+
+ if (m_iNextStart < chars.length) {
+ spaceIPD.add(pendingSpace.resolve(false));
+ }
+ else {
+ // This FO ended with spaces. Return the BP
+ iFlags |= BreakPoss.ALL_ARE_SUPPRESS_AT_LB;
+ // lc.trailingSpaceSeq.addSpace(m_halfWS);
+ // Need to make SpaceSpecifier from m_halfWS!
+ // Or at least a spaceval
+ return makeBreakPoss(iThisStart, spaceIPD, 0, pendingSpace,
+ iFlags);
+ }
+
+ // Look for a legal line-break: breakable white-space and certain
+ // characters such as '-' which can serve as word breaks.
+ // Don't look for hyphenation points here though
+
+ for (; m_iNextStart < chars.length; m_iNextStart++) {
+ char c = chars[m_iNextStart];
+ if ((c == NEWLINE) ||
+ // Include any breakable white-space as break char
+ // even if fixed width
+ (textInfo.bWrap &&
+ (CharUtilities.isSpace(c) ||
+ s_breakChars.indexOf(c)>=0))) {
+ iFlags |= BreakPoss.CAN_BREAK_AFTER;
+ if (c != SPACE) {
+ m_iNextStart++;
+ if (c != NEWLINE) {
+ wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
+ }
+ else {
+ iFlags |= BreakPoss.FORCE;
+ }
+ }
+ return makeBreakPoss(iThisStart, spaceIPD, wordIPD, null,
+ iFlags);
+ }
+ wordIPD += CharUtilities.getCharWidth(c, textInfo.fs);
+ // Note, if a normal non-breaking space, is it stretchable???
+ // If so, keep a count of these embedded spaces.
+ }
+ return makeBreakPoss(iThisStart, spaceIPD, wordIPD, null, iFlags);
+ }
+
+
+ private BreakPoss makeBreakPoss(short iWordStart, MinOptMax spaceIPD,
+ int wordDim,
+ SpaceSpecifier trailingSpace,
+ int flags)
+ {
+ MinOptMax ipd = new MinOptMax(wordDim);
+ ipd.add(spaceIPD);
+
+ // Position is the index of the info for this word in the vector
+ m_vecAreaInfo.add(new AreaInfo(iWordStart, m_iNextStart, ipd));
+ BreakPoss bp =
+ new BreakPoss(this,
+ new TextBreakPosition(m_vecAreaInfo.size()-1));
+
+ ipd.add(m_ipdTotal); // sum of all words so far in line
+ bp.setStackingSize(ipd);
+ m_ipdTotal = ipd;
+ // TODO: make this correct (see Keiron's code below!)
+ bp.setNonStackingSize(new MinOptMax(textInfo.lineHeight));
+
+ /* Set max ascender and descender (offset from baseline),
+ * used for calculating the bpd of the line area containing
+ * this text.
+ */
+ //bp.setDescender(textInfo.fs.getDescender());
+ //bp.setAscender(textInfo.fs.getAscender());
+ if (m_iNextStart == chars.length) {
+ flags |= BreakPoss.ISLAST;
+ setFinished(true);
+ }
+ bp.setFlag(flags);
+ if (trailingSpace != null) {
+ bp.setTrailingSpace(trailingSpace);
+ }
+ return bp;
+ }
+
+
+ /**
+ * Add an area for each word and space (or one big one????)
+ */
+ public void addAreas(PositionIterator posIter) {
+ // Add word areas
+ TextBreakPosition tbpStart, tbpNext;
+ while (posIter.hasNext()) {
+ tbpNext = (TextBreakPosition)posIter.next();
+ // System.err.println("tbp.pos = " + tbpNext.m_iAreaIndex);
+ AreaInfo ai = (AreaInfo)m_vecAreaInfo.
+ elementAt(tbpNext.m_iAreaIndex);
+ // Make an area containing all characters between start and end.
+ Word word = createWord(new String(chars, ai.m_iStartIndex,
+ ai.m_iBreakIndex- ai.m_iStartIndex),
+ ai.m_ipdArea.opt);
+ parentLM.addChild(word);
+ }
+ }
+
+
+
+ protected Word createWord(String str, int width) {
+ Word curWordArea = new Word();
+ curWordArea.setWidth(width);
+ curWordArea.setHeight(textInfo.fs.getAscender() - textInfo.fs.getDescender());
+ curWordArea.setOffset(textInfo.fs.getAscender());
+ curWordArea.info = new LayoutInfo();
+ curWordArea.info.lead = textInfo.fs.getAscender();
+ curWordArea.info.alignment = VerticalAlign.BASELINE;
+ curWordArea.info.blOffset = true;
+
+ curWordArea.setWord(str);
+ Trait prop = new Trait();
+ prop.propType = Trait.FONT_STATE;
+ prop.data = textInfo.fs;
+ curWordArea.addTrait(prop);
+ return curWordArea;
+ }
+
+
+}
+