diff options
author | Karen Lease <klease@apache.org> | 2002-05-10 12:38:16 +0000 |
---|---|---|
committer | Karen Lease <klease@apache.org> | 2002-05-10 12:38:16 +0000 |
commit | b45cb4b5005f233e501e3ab815d362539af885e3 (patch) | |
tree | a133ffe50858fd97b1d58883db9a08db62651e5c /src | |
parent | db755bf42556bc19d396ae22cb919fdb995fe4cf (diff) | |
download | xmlgraphics-fop-b45cb4b5005f233e501e3ab815d362539af885e3.tar.gz xmlgraphics-fop-b45cb4b5005f233e501e3ab815d362539af885e3.zip |
Add support for line-breaking in nested inlines using BreakPoss strategy
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@194818 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
-rw-r--r-- | src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java | 73 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/BPLayoutManager.java | 4 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/BlockLayoutManager.java | 4 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/BreakPoss.java | 6 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/BreakPossPosIter.java | 8 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java | 353 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/LMiter.java | 88 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/LineBPLayoutManager.java | 107 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/LineLayoutManager.java | 2 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/SpaceSpecifier.java | 15 | ||||
-rw-r--r-- | src/org/apache/fop/layoutmgr/TextBPLayoutManager.java | 40 | ||||
-rw-r--r-- | src/org/apache/fop/render/AbstractRenderer.java | 11 | ||||
-rw-r--r-- | src/org/apache/fop/render/Renderer.java | 2 | ||||
-rw-r--r-- | src/org/apache/fop/render/xml/XMLRenderer.java | 11 |
14 files changed, 619 insertions, 105 deletions
diff --git a/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java index 9a0218f74..b3b3ffa01 100644 --- a/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/AbstractBPLayoutManager.java @@ -24,10 +24,78 @@ public abstract class AbstractBPLayoutManager extends AbstractLayoutManager /** True if this LayoutManager has handled all of its content. */ private boolean m_bFinished = false; + private BPLayoutManager m_curChildLM=null; + private ListIterator m_childLMiter; + private boolean m_bInited=false; public AbstractBPLayoutManager(FObj fobj) { + this(fobj, new LMiter(fobj.getChildren())); + } + + + public AbstractBPLayoutManager(FObj fobj, ListIterator lmIter) { super(fobj); + m_childLMiter = lmIter; + } + + + /** + * Return currently active child LayoutManager or null if + * all children have finished layout. + * Note: child must implement BPLayoutManager! If it doesn't, skip it + * and print a warning. + */ + protected 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); + m_curChildLM.init(); + return m_curChildLM; + } + else { + m_childLMiter.remove(); + System.err.println("WARNING: child LM 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. + */ + protected void reset(LayoutManager lm, BreakPoss.Position pos) { + //if (lm == null) return; + if (m_curChildLM != lm) { + // ASSERT m_curChildLM == (BPLayoutManager)m_childLMiter.previous() + if (m_curChildLM != (BPLayoutManager)m_childLMiter.previous()) { + System.err.println("LMiter problem!"); + } + while (m_curChildLM != lm && m_childLMiter.hasPrevious()) { + m_curChildLM.resetPosition(null); + m_curChildLM = (BPLayoutManager)m_childLMiter.previous(); + } + m_childLMiter.next(); // Otherwise next returns same object + } + m_curChildLM.resetPosition(pos); + if (isFinished()) { + setFinished(false); + } + } + + public void resetPosition(BreakPoss.Position resetPos) { + if (resetPos == null) { + reset(null, null); + } } @@ -35,9 +103,10 @@ public abstract class AbstractBPLayoutManager extends AbstractLayoutManager * 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) { + public void init() { + if (fobj != null && m_bInited == false) { initProperties(fobj.getPropertyManager()); + m_bInited=true; } } diff --git a/src/org/apache/fop/layoutmgr/BPLayoutManager.java b/src/org/apache/fop/layoutmgr/BPLayoutManager.java index 34bb5b126..32f7df9d7 100644 --- a/src/org/apache/fop/layoutmgr/BPLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/BPLayoutManager.java @@ -64,4 +64,8 @@ public interface BPLayoutManager extends LayoutManager { */ public void addAreas(PositionIterator posIter) ; + public void init() ; + + public void resetPosition(BreakPoss.Position position); + } diff --git a/src/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/org/apache/fop/layoutmgr/BlockLayoutManager.java index d53511bd0..b82ba2edb 100644 --- a/src/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -83,13 +83,13 @@ public class BlockLayoutManager extends BlockStackingLayoutManager { break; } } + /* lm = new LineLayoutManager(curFobj, inlines, lineHeight, lead, follow); + */ // !!!! To test BreakPoss Line LayoutManager, uncomment! - /* lm = new LineBPLayoutManager(curFobj, inlines, lineHeight, lead, follow); - */ lms.set(count, lm); } lm.setParentLM(this); diff --git a/src/org/apache/fop/layoutmgr/BreakPoss.java b/src/org/apache/fop/layoutmgr/BreakPoss.java index eb4ad4200..80fa797c7 100644 --- a/src/org/apache/fop/layoutmgr/BreakPoss.java +++ b/src/org/apache/fop/layoutmgr/BreakPoss.java @@ -84,7 +84,7 @@ public class BreakPoss { this(lm,position,0); } - public BreakPoss(BPLayoutManager lm, Position position, int flags) { + public BreakPoss(BPLayoutManager lm, Position position, long flags) { m_lm = lm; m_position = position; m_flags = flags; @@ -128,6 +128,10 @@ public class BreakPoss { return this.m_nonStackSize ; } + public long getFlags() { + return m_flags; + } + public void setFlag(int flagBit) { setFlag(flagBit, true); } diff --git a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java index 0188b2731..a868ac5e5 100644 --- a/src/org/apache/fop/layoutmgr/BreakPossPosIter.java +++ b/src/org/apache/fop/layoutmgr/BreakPossPosIter.java @@ -21,7 +21,13 @@ public class BreakPossPosIter extends PositionIterator { // Check position < endPos protected boolean checkNext() { - return (m_iterCount > 0 && super.checkNext()); + if (m_iterCount > 0) { + return super.checkNext(); + } + else { + endIter(); + return false; + } } public Object next() { diff --git a/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java new file mode 100644 index 000000000..be87055c4 --- /dev/null +++ b/src/org/apache/fop/layoutmgr/InlineStackingBPLayoutManager.java @@ -0,0 +1,353 @@ +/* + * $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.layout.BorderAndPadding; +import org.apache.fop.traits.InlineProps; +import org.apache.fop.area.Area; +import org.apache.fop.area.MinOptMax; +import org.apache.fop.area.inline.InlineArea; +import org.apache.fop.area.inline.InlineParent; + +import java.util.Iterator; +import java.util.ListIterator; + +/** + * LayoutManager for objects which stack children in the inline direction, + * such as Inline or Line + */ +public class InlineStackingBPLayoutManager extends AbstractBPLayoutManager { + + /** + * Private class to store information about a lower-level BreakPosition. + * Note: fields are directly readable in this class + */ + private static class WrappedPosition implements BreakPoss.Position { + BPLayoutManager m_childLM; + BreakPoss.Position m_childPosition; + + WrappedPosition(BPLayoutManager childLM, + BreakPoss.Position childPosition) { + m_childLM = childLM; + m_childPosition = childPosition; + } + } + + private static class StackingIter extends PositionIterator { + + StackingIter(Iterator parentIter) { + super(parentIter); + } + + protected BPLayoutManager getLM(Object nextObj) { + return ((WrappedPosition)nextObj).m_childLM; + } + + protected BreakPoss.Position getPos(Object nextObj) { + return ((WrappedPosition)nextObj).m_childPosition; + } + + } + + + /** + * 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); + + /** + * Size of border and padding in BPD (ie, before and after). + */ + 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; + + public InlineStackingBPLayoutManager(FObj fobj, ListIterator childLMiter) { + super(fobj, childLMiter); + m_bFirstArea = true; + // Initialize inline properties (borders, padding, space) + // initProperties(); + } + + public boolean generatesInlineAreas() { + return true; + } + + protected void initProperties(PropertyManager propMgr) { + // super.initProperties(propMgr); + System.err.println("InlineStackingBPLayoutManager.initProperties called"); + m_inlineProps = propMgr.getInlineProps(); + m_borderProps = propMgr.getBorderAndPadding(); + // Calculdate border and padding size in BPD + int iPad = m_borderProps.getPadding(BorderAndPadding.BEFORE, false); + iPad += m_borderProps.getBorderWidth(BorderAndPadding.BEFORE, false); + iPad += m_borderProps.getPadding(BorderAndPadding.AFTER, false); + iPad += m_borderProps.getBorderWidth(BorderAndPadding.AFTER, false); + m_extraBPD = new MinOptMax(iPad); + } + + private MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) { + int iBP = m_borderProps.getPadding(BorderAndPadding.START, bNotFirst); + iBP += m_borderProps.getBorderWidth(BorderAndPadding.START, bNotFirst); + iBP += m_borderProps.getPadding(BorderAndPadding.END, bNotLast); + iBP += m_borderProps.getBorderWidth(BorderAndPadding.END, bNotLast); + return new MinOptMax(iBP); + } + + private 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) { + int iBP = m_borderProps.getPadding(BorderAndPadding.END, bNotLast); + iBP += m_borderProps.getBorderWidth(BorderAndPadding.END, bNotLast); + return (iBP > 0); + } + + + /** Reset position for returning next BreakPossibility. */ + + public void resetPosition(BreakPoss.Position prevPos) { + WrappedPosition wrappedPos = (WrappedPosition)prevPos; + if (wrappedPos != null) { + // Back up the layout manager iterator + reset(wrappedPos.m_childLM, wrappedPos.m_childPosition); + } + else { + // Backup to first child layout manager + System.err.println("InlineStackingBPLM: resetPosition(null)"); + super.resetPosition(prevPos); + } + // Do we need to reset some context like pending or prevContent? + } + + + /** + * 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 any space-start, border-start or padding-start, else + * propagate to first child LM + */ + public boolean canBreakBefore(LayoutContext context) { + if (m_inlineProps.spaceStart.space.min > 0 || + hasLeadingFence(false)) { + return true; + } + BPLayoutManager lm = getChildLM(); + if (lm != null) { + return lm.canBreakBefore(context); + } + else return false; // ??? NO child LM? + } + + + 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 + // not be the first area created by this inline + lc.getPendingSpace().addSpace(m_inlineProps.spaceStart); + // Check for "fence" + if (hasLeadingFence(!m_bFirstArea)) { + bIncludeStartSpace=true; + // Reset leading space sequence for child areas + childLC.setPendingSpace(new SpaceSpecifier(false)); + } + // Reset state variables + m_pendingIPD = new MinOptMax(0); + m_prevContentIPD = new MinOptMax(0); + } + 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); +// } + + 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 (((bp = curLM.getNextBreakPoss(childLC)) != null)) { + // && couldEndLine(bp)) { + break; + } +// if (bp.isLastArea()) { +// // NORMALLY IT MUST BE! +// m_pendingIPD.add(bp.getStackingSize()); +// m_prevBP = bp; +// } + } + if (bp==null) { + setFinished(true); + return null; // There was no childLM + // 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); + } + } + + 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) { + WrappedPosition inlbp = + new WrappedPosition(bp.getLayoutManager(), bp.getPosition()); + BreakPoss myBP = new BreakPoss(this, inlbp, bp.getFlags()); + + // Update dimension information for our allocation area, + // including child areas + // generated by previous childLM which have completed layout + // Update pending area measure + // This includes all previous breakinfo + + MinOptMax bpDim = (MinOptMax)bp.getStackingSize().clone(); + + 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 + + } + + // Start and end borders and padding + bpDim.add(m_prevContentIPD); + bpDim.add(getExtraIPD(!bIsFirst, !bIsLast)); + myBP.setStackingSize(bpDim); + myBP.setNonStackingSize(MinOptMax.add(bp.getNonStackingSize(), + m_extraBPD)); + 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; + } + + + + /****** + protected BreakableText getText(BreakPoss prevBP, BreakPoss lastBP) { + } + *****/ + + // Generate and add areas to parent area + // Set size etc + public void addAreas(PositionIterator parentIter) { + // Make areas from start to end + // Update childLM based on bpEnd + // It might be a previous sibling of the current one! + + m_inlineArea = new InlineParent(); + + // Note: if first, bpStart is perhaps null???? + // If we are first in parent, set ISFIRST... + + + // posIter iterates over positions returned by this LM + StackingIter childPosIter = new StackingIter(parentIter); + BPLayoutManager childLM ; + while ((childLM = childPosIter.getNextChildLM())!= null) { + childLM.addAreas(childPosIter); + } + + parentLM.addChild(m_inlineArea); + } + + +// protected Area createArea() { +// return new InlineParent(); +// } + + public boolean addChild(Area childArea) { + // Make sure childArea is inline area + if (childArea instanceof InlineArea) { + m_inlineArea.addChild((InlineArea)childArea); + } + return false; + } + + +} diff --git a/src/org/apache/fop/layoutmgr/LMiter.java b/src/org/apache/fop/layoutmgr/LMiter.java new file mode 100644 index 000000000..fcb94748b --- /dev/null +++ b/src/org/apache/fop/layoutmgr/LMiter.java @@ -0,0 +1,88 @@ +/* + * $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 java.util.ArrayList; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +public class LMiter implements ListIterator { + + + private ListIterator m_baseIter; + private FObj m_curFO; + private ArrayList m_listLMs; + private int m_curPos=0; + + public LMiter(ListIterator baseIter) { + m_baseIter = baseIter; + m_listLMs = new ArrayList(10); + } + + public boolean hasNext() { + return (m_curPos < m_listLMs.size())? true : + preLoadNext(); + } + + private boolean preLoadNext() { + if (m_baseIter.hasNext()) { + FObj fobj = (FObj)m_baseIter.next(); + //m_listLMs.add(fobj.getLayoutManager()); + fobj.addLayoutManager(m_listLMs); + return true; + } + else return false; + } + + public boolean hasPrevious() { + return (m_curPos > 0); + } + + public Object previous() throws NoSuchElementException { + if (m_curPos > 0) { + return m_listLMs.get(--m_curPos); + } + else throw new NoSuchElementException(); + } + + public Object next() throws NoSuchElementException { + if (m_curPos < m_listLMs.size()) { + return m_listLMs.get(m_curPos++); + } + else throw new NoSuchElementException(); + } + + public void remove() throws NoSuchElementException { + if (m_curPos > 0) { + m_listLMs.remove(--m_curPos); + // Note: doesn't actually remove it from the base! + } + else throw new NoSuchElementException(); + + } + + + public void add(Object o) throws UnsupportedOperationException { + throw new UnsupportedOperationException("LMiter doesn't support add"); + } + + public void set(Object o) throws UnsupportedOperationException { + throw new UnsupportedOperationException("LMiter doesn't support set"); + } + + public int nextIndex() { + return m_curPos; + } + + public int previousIndex() { + return m_curPos - 1; + } + +} diff --git a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java index 86417d024..71339821d 100644 --- a/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/LineBPLayoutManager.java @@ -33,7 +33,8 @@ 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 { +public class LineBPLayoutManager extends + InlineStackingBPLayoutManager { /** * Private class to store information about inline breaks. @@ -48,8 +49,6 @@ public class LineBPLayoutManager extends LineLayoutManager { } } - private BPLayoutManager m_curChildLM=null; - private ListIterator m_childLMiter; private LineArea m_lineArea; // LineArea currently being filled @@ -64,13 +63,13 @@ public class LineBPLayoutManager extends LineLayoutManager { public LineBPLayoutManager(FObj fobj, List lms, int lh, int l, int f) { - super(fobj, lms, lh, l, f); - m_childLMiter = lms.listIterator(); - initProperties(); + //super(fobj, lms, lh, l, f); + super(fobj, lms.listIterator()); + // initProperties(); } protected void initProperties(PropertyManager propMgr) { - super.initProperties(propMgr); + // super.initProperties(propMgr); System.err.println("LineBPLayoutManager.initProperties called"); MarginProps marginProps = propMgr.getMarginProps(); m_iIndents = marginProps.startIndent + marginProps.endIndent; @@ -80,47 +79,6 @@ public class LineBPLayoutManager extends LineLayoutManager { } - /** - * 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 @@ -183,10 +141,7 @@ public class LineBPLayoutManager extends LineLayoutManager { 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) { + if ((bp = curLM.getNextBreakPoss(inlineLC, null)) != null) { // check if this bp fits in line MinOptMax bpDim = (MinOptMax)bp.getStackingSize().clone(); /* If first BP for this LM (in this call) @@ -232,8 +187,12 @@ public class LineBPLayoutManager extends LineLayoutManager { * This includes any previosly pending size, * already calculated above. */ - pendingIPD = bpDim; - // Add BP to the pending list + 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) { @@ -290,36 +249,17 @@ public class LineBPLayoutManager extends LineLayoutManager { // No more content to layout! setFinished(true); } - // Backup layoutmanager if necessary - resetChildLM(m_prevBP.getLayoutManager()); + // Backup child LM if necessary + if (bp != m_prevBP) { + // Remove any pending breaks from the vector + while (m_vecInlineBreaks.lastElement()!=m_prevBP) { + m_vecInlineBreaks.remove(m_vecInlineBreaks.size()-1); + } + reset(m_prevBP.getLayoutManager(), m_prevBP.getPosition()); + } 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) { @@ -356,11 +296,10 @@ public class LineBPLayoutManager extends LineLayoutManager { new BreakPossPosIter(m_vecInlineBreaks, iStartPos, lbp.m_iPos+1); iStartPos = lbp.m_iPos+1; - while (inlinePosIter.hasNext() && - (childLM = inlinePosIter.getNextChildLM())!= null) { + while ((childLM = inlinePosIter.getNextChildLM())!= null) { childLM.addAreas(inlinePosIter); } - verticalAlign(m_lineArea); + // verticalAlign(m_lineArea); parentLM.addChild(m_lineArea); } m_lineArea = null; diff --git a/src/org/apache/fop/layoutmgr/LineLayoutManager.java b/src/org/apache/fop/layoutmgr/LineLayoutManager.java index 4a33190fb..6e8050996 100644 --- a/src/org/apache/fop/layoutmgr/LineLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/LineLayoutManager.java @@ -44,7 +44,7 @@ import java.util.Iterator; * * How do we handle Unicode BIDI? */ -public class LineLayoutManager extends AbstractBPLayoutManager { +public class LineLayoutManager extends AbstractLayoutManager { private LineInfo currentLine = null; private boolean bFirstLine = true; private MinOptMax totalIPD; diff --git a/src/org/apache/fop/layoutmgr/SpaceSpecifier.java b/src/org/apache/fop/layoutmgr/SpaceSpecifier.java index 2908fe5aa..ad7193c4e 100644 --- a/src/org/apache/fop/layoutmgr/SpaceSpecifier.java +++ b/src/org/apache/fop/layoutmgr/SpaceSpecifier.java @@ -16,7 +16,7 @@ import java.util.Vector; * areas with a stacking constraint. Provide a way to resolve these into * a single MinOptMax value. */ -public class SpaceSpecifier { +public class SpaceSpecifier implements Cloneable { private boolean m_bStartsRefArea; @@ -28,6 +28,19 @@ public class SpaceSpecifier { m_bStartsRefArea = bStartsRefArea; } + public Object clone() { + try { + SpaceSpecifier ss = (SpaceSpecifier)super.clone(); + // Clone the vector, but share the objects in it! + ss.m_vecSpaceVals = new Vector(this.m_vecSpaceVals.size()); + ss.m_vecSpaceVals.addAll(this.m_vecSpaceVals); + return ss; + } catch (CloneNotSupportedException cnse) { + return null; + } + + } + /** * Clear all space specifiers and fences. */ diff --git a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java index 8c99cbc3b..b0c28ec17 100644 --- a/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java +++ b/src/org/apache/fop/layoutmgr/TextBPLayoutManager.java @@ -195,6 +195,30 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager { (CharUtilities.isSpace(c) || s_breakChars.indexOf(c)>=0))); } + /** Reset position for returning next BreakPossibility. */ + + public void resetPosition(BreakPoss.Position prevPos) { + 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"); + setFinished(false); + } + } + else { + // Reset to beginning! + System.err.println("TextBPLM: resetPosition(null)"); + m_vecAreaInfo.setSize(0); + m_iNextStart = 0; + setFinished(false); + } + } + + /** * Return the next break possibility that fits the constraints. * @param context An object specifying the flags and input information @@ -229,17 +253,6 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager { 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) { @@ -249,6 +262,7 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager { chars[m_iNextStart]==SPACE; m_iNextStart++); // If now at end, nothing to compose here! if (m_iNextStart >= chars.length) { + setFinished(true); return null; // Or an "empty" BreakPoss? } } @@ -364,6 +378,10 @@ public class TextBPLayoutManager extends AbstractBPLayoutManager { if (trailingSpace != null) { bp.setTrailingSpace(trailingSpace); } + else { + bp.setTrailingSpace(new SpaceSpecifier(false)); + } + bp.setLeadingSpace(new SpaceSpecifier(false)); return bp; } diff --git a/src/org/apache/fop/render/AbstractRenderer.java b/src/org/apache/fop/render/AbstractRenderer.java index 9f564bf97..ddbece58f 100644 --- a/src/org/apache/fop/render/AbstractRenderer.java +++ b/src/org/apache/fop/render/AbstractRenderer.java @@ -10,10 +10,8 @@ package org.apache.fop.render; // FOP import org.apache.fop.apps.FOPException; import org.apache.fop.area.*; -import org.apache.fop.area.Span; import org.apache.fop.area.inline.*; import org.apache.fop.area.inline.Character; -import org.apache.fop.area.inline.Space; import org.apache.fop.fo.FOUserAgent; // Avalon @@ -25,6 +23,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.List; +import java.util.Iterator; /** * Abstract base class for all renderers. @@ -308,6 +307,14 @@ public abstract class AbstractRenderer implements Renderer { currentBlockIPPosition += word.getWidth(); } + public void renderInlineParent(InlineParent ip) { + // currentBlockIPPosition += ip.getWidth(); + Iterator iter = ip.getChildAreas().iterator(); + while (iter.hasNext()) { + ((InlineArea)iter.next()).render(this); + } + } + protected void renderBlocks(List blocks) { for (int count = 0; count < blocks.size(); count++) { Object obj = blocks.get(count); diff --git a/src/org/apache/fop/render/Renderer.java b/src/org/apache/fop/render/Renderer.java index a40de294a..488c4aad2 100644 --- a/src/org/apache/fop/render/Renderer.java +++ b/src/org/apache/fop/render/Renderer.java @@ -75,6 +75,8 @@ public interface Renderer { public void renderWord(Word area); + public void renderInlineParent(InlineParent ip); + public void renderCharacter( org.apache.fop.area.inline.Character ch); diff --git a/src/org/apache/fop/render/xml/XMLRenderer.java b/src/org/apache/fop/render/xml/XMLRenderer.java index 94ef5b1d2..85aa688ef 100644 --- a/src/org/apache/fop/render/xml/XMLRenderer.java +++ b/src/org/apache/fop/render/xml/XMLRenderer.java @@ -348,6 +348,17 @@ public class XMLRenderer extends AbstractRenderer { super.renderWord(word); } + public void renderInlineParent(InlineParent ip) { + String prop = ""; + List list = ip.getTraitList(); + if (list != null) { + prop = " props=\"" + getPropString(list) + "\""; + } + writeStartTag("<inlineparent" + prop + ">"); + super.renderInlineParent(ip); + writeEndTag("</inlineparent>"); + } + public void renderLeader(Leader area) { String style = "solid"; switch (area.getRuleStyle()) { |