]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Merged branch https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/inlineblock...
authorJeremias Maerki <jeremias@apache.org>
Fri, 12 Aug 2005 09:50:01 +0000 (09:50 +0000)
committerJeremias Maerki <jeremias@apache.org>
Fri, 12 Aug 2005 09:50:01 +0000 (09:50 +0000)
Revisions: 227462 to HEAD (231261)

This adds support for block-level content inside fo:inline.

The full set of changes on the branch can be extracted by:
svn log http://svn.apache.org/repos/asf/xmlgraphics/fop/branches/inlineblock -r 227462:231261

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@232250 13f79535-47bb-0310-9956-ffa450edef68

22 files changed:
src/java/org/apache/fop/area/LineArea.java
src/java/org/apache/fop/area/inline/InlineBlockParent.java [new file with mode: 0644]
src/java/org/apache/fop/fo/NullCharIterator.java [new file with mode: 0644]
src/java/org/apache/fop/fo/flow/Block.java
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/KnuthSequence.java
src/java/org/apache/fop/layoutmgr/LayoutContext.java
src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
src/java/org/apache/fop/render/AbstractRenderer.java
src/java/org/apache/fop/render/pdf/PDFRenderer.java
src/java/org/apache/fop/render/xml/XMLRenderer.java
test/java/org/apache/fop/logging/LoggingElementListObserver.java
test/layoutengine/disabled-testcases.txt
test/layoutengine/testcases/inline-block1.xml [new file with mode: 0644]
test/layoutengine/testcases/inline-block2.xml [new file with mode: 0644]
test/layoutengine/testcases/inline1.xml

index 12a5fb61c72f5238ed9b32cb34797bf5dbffd5dd..593b9077ea27ad5647c5adcd7272efbaef4afc46 100644 (file)
@@ -91,5 +91,19 @@ public class LineArea extends Area {
     public int getStartIndent() {
         return startIndent;
     }
+
+    /**
+     * Updates the extents of the line area from its children.
+     */
+    public void updateExtentsFromChildren() {
+        int ipd = 0;
+        int bpd = 0;
+        for (int i = 0, len = inlineAreas.size(); i < len; i++) {
+            ipd = Math.max(ipd, ((InlineArea)inlineAreas.get(i)).getAllocIPD());
+            bpd += ((InlineArea)inlineAreas.get(i)).getAllocBPD();
+        }
+        setIPD(ipd);
+        setBPD(bpd);
+    }
 }
 
diff --git a/src/java/org/apache/fop/area/inline/InlineBlockParent.java b/src/java/org/apache/fop/area/inline/InlineBlockParent.java
new file mode 100644 (file)
index 0000000..9934b13
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.area.inline;
+
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+
+
+/**
+ * Inline block parent area.
+ * This is an inline area that can have one block area as a child
+ */
+public class InlineBlockParent extends InlineArea {
+
+    /**
+     * The list of inline areas added to this inline parent.
+     */
+    protected Block child = null;
+
+    /**
+     * Create a new inline block parent to add areas to.
+     */
+    public InlineBlockParent() {
+    }
+
+    /**
+     * Override generic Area method.
+     *
+     * @param childArea the child area to add
+     */
+    public void addChildArea(Area childArea) {
+        if (child != null) {
+            throw new IllegalStateException("InlineBlockParent may have only one child area.");
+        }
+        if (childArea instanceof Block) {
+            child = (Block) childArea;
+            //Update extents from the child
+            setIPD(childArea.getAllocIPD());
+            setBPD(childArea.getAllocBPD());
+        } else {
+            throw new IllegalArgumentException("The child of an InlineBlockParent must be a"
+                    + " Block area");
+        }
+    }
+
+    /**
+     * Get the child areas for this inline parent.
+     *
+     * @return the list of child areas
+     */
+    public Block getChildArea() {
+        return child;
+    }
+
+}
diff --git a/src/java/org/apache/fop/fo/NullCharIterator.java b/src/java/org/apache/fop/fo/NullCharIterator.java
new file mode 100644 (file)
index 0000000..01c054c
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.fo;
+
+import java.util.NoSuchElementException;
+
+/**
+ * Class providing an iterator for zero characters. Used by the Block FO.
+ */
+public class NullCharIterator extends CharIterator {
+
+    private static CharIterator instance;
+    
+    public static CharIterator getInstance() {
+        if (instance == null) {
+            instance = new NullCharIterator();
+        }
+        return instance;
+    }
+
+    /**
+     * Constructor
+     */
+    public NullCharIterator() {
+        //nop
+    }
+
+    /** @see java.util.Iterator#hasNext() */
+    public boolean hasNext() {
+        return false;
+    }
+
+    /** @see org.apache.fop.fo.CharIterator#nextChar() */
+    public char nextChar() throws NoSuchElementException {
+        throw new NoSuchElementException();
+    }
+
+}
+
index 50f04a28ea047dfe10261bb1fa269c60f984cf19..f5d8ceb052d659194a5ce2c193880bf1eae41419 100644 (file)
@@ -29,6 +29,7 @@ import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.FOText;
 import org.apache.fop.fo.FObjMixed;
+import org.apache.fop.fo.NullCharIterator;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.PropertySets;
 import org.apache.fop.fo.RecursiveCharIterator;
@@ -507,6 +508,11 @@ public class Block extends FObjMixed {
         }
     }
      
+    /** @see org.apache.fop.fo.FONode#charIterator() */
+    public CharIterator charIterator() {
+        return NullCharIterator.getInstance();
+    }
+
     /**
      * @see org.apache.fop.fo.FONode#getName()
      */
index d091c73e5abda1306ad3fa88781f35be0dedb047..cd011b36674da8473da5f0e25aa3125e777be517 100644 (file)
@@ -187,6 +187,7 @@ public abstract class AbstractBreaker {
             alignment = Constants.EN_START;
         }
         alignmentLast = Constants.EN_START;
+        childLC.setBPAlignment(alignment);
 
         BlockSequence blockList;
         blockLists = new java.util.ArrayList();
index 636055cb5780a43ccd4ee2404b250502dd4a6a14..45e2945fae7d92a547a928f296662082ef21e9b0 100644 (file)
@@ -166,7 +166,10 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
      */
     public boolean mustKeepTogether() {
         //TODO Keeps will have to be more sophisticated sooner or later
-        return ((BlockLevelLayoutManager)getParent()).mustKeepTogether() 
+        // TODO This is a quick fix for the fact that the parent is not always a BlockLevelLM;
+        // eventually mustKeepTogether() must be moved up to the LM interface
+        return (getParent() instanceof BlockLevelLayoutManager
+                && ((BlockLevelLayoutManager) getParent()).mustKeepTogether()) 
                 || !getBlockFO().getKeepTogether().getWithinPage().isAuto()
                 || !getBlockFO().getKeepTogether().getWithinColumn().isAuto();
     }
@@ -303,7 +306,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager {
                     splitLength += element.getW();
                     lastLM = element.getLayoutManager();
                 }
-                }
+            }
             //System.out.println("addAreas riferito a storedList da " +
                   // iFirst + " a " + iLast);
             //System.out.println("splitLength= " + splitLength
index e757cb002d2c73082180c58ce3c9b6906314d1af..77f30f1c5c42c248cd0f61fd0f1597ca5c0de662 100644 (file)
@@ -28,6 +28,8 @@ public class KnuthSequence extends ArrayList {
     public int ignoreAtStart = 0;
     /** Number of elements to ignore at the end of the list. */
     public int ignoreAtEnd = 0;
+    // Is this an inline or a block sequence?
+    private boolean isInlineSequence = false;
 
     /**
      * Creates a new and empty list.
@@ -36,6 +38,14 @@ public class KnuthSequence extends ArrayList {
         super();
     }
 
+    /**
+     * Creates a new and empty list, and sets isInlineSequence.
+     */
+    public KnuthSequence(boolean isInlineSequence) {
+        super();
+        this.isInlineSequence = isInlineSequence;
+    }
+
     /**
      * Marks the start of the sequence.
      */
@@ -84,4 +94,12 @@ public class KnuthSequence extends ArrayList {
     public KnuthElement getElement(int index) {
         return (KnuthElement) get(index);
     }
+
+    /**
+     * Is this an inline or a block sequence?
+     * @return true if this is an inline sequence
+     */
+    public boolean isInlineSequence() {
+        return isInlineSequence;
+    }
 }
index 2d3323625996939646e24ce65f148794b87b432e..f63f23ccf67c2dfad395c17ed4a5ed261b7c92df 100644 (file)
@@ -91,6 +91,9 @@ public class LayoutContext {
     /** Current hyphenation context. May be null. */
     private HyphContext hyphContext = null;
 
+    /** Alignment in BP direction */
+    private int bpAlignment = Constants.EN_START;
+    
     /** Stretch or shrink value when making areas. */
     private double ipdAdjust = 0.0;
 
@@ -112,6 +115,7 @@ public class LayoutContext {
         this.leadingSpace = parentLC.leadingSpace; //???
         this.trailingSpace = parentLC.trailingSpace; //???
         this.hyphContext = parentLC.hyphContext;
+        this.bpAlignment = parentLC.bpAlignment;
         this.dSpaceAdjust = parentLC.dSpaceAdjust;
         this.ipdAdjust = parentLC.ipdAdjust;
         this.iLineHeight = parentLC.iLineHeight;
@@ -224,6 +228,19 @@ public class LayoutContext {
         return ((this.flags & TRY_HYPHENATE) != 0);
     }
 
+    /**
+     * Sets the currently applicable alignment in BP direction.
+     * @param alignment one of EN_START, EN_JUSTIFY etc.
+     */
+    public void setBPAlignment(int alignment) {
+        this.bpAlignment = alignment;
+    }
+    
+    /** @return the currently applicable alignment in BP direction (EN_START, EN_JUSTIFY...) */
+    public int getBPAlignment() {
+        return this.bpAlignment;
+    }
+    
     public void setSpaceAdjust(double adjust) {
         dSpaceAdjust = adjust;
     }
index 9dd0abbcb8b2de44be6b047020401096bb46483a..c6d5c4bf7b50863e15ffb1e89e89b660a856486f 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.fop.layoutmgr.inline;
 
 import org.apache.fop.fo.flow.BasicLink;
 import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.area.inline.InlineArea;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.Trait;
 import org.apache.fop.area.LinkResolver;
@@ -41,14 +42,14 @@ public class BasicLinkLayoutManager extends InlineLayoutManager {
         fobj = node;
     }
 
-    protected InlineParent createArea() {
-        InlineParent area = super.createArea();
+    protected InlineArea createArea(boolean bInlineParent) {
+        InlineArea area = super.createArea(bInlineParent);
         setupBasicLinkArea(parentLM, area);
         return area;
     }
     
     private void setupBasicLinkArea(LayoutManager parentLM,
-                                      InlineParent area) {
+                                      InlineArea area) {
          if (fobj.getExternalDestination() != null) {
              area.addTrait(Trait.EXTERNAL_LINK, fobj.getExternalDestination());
          } else {
index e39292f62b975538557b11e4aa4f4c11ec89d4ff..779c4c5879715b4fed756bec238a6aa99ccdf649 100644 (file)
@@ -26,6 +26,7 @@ import org.apache.fop.fo.flow.Footnote;
 import org.apache.fop.layoutmgr.AbstractLayoutManager;
 import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
 import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.Position;
 
@@ -45,7 +46,7 @@ public class FootnoteLayoutManager extends AbstractLayoutManager
         footnote = node;
 
         // create an InlineStackingLM handling the fo:inline child of fo:footnote
-        citationLM = new InlineStackingLayoutManager(footnote.getFootnoteCitation());
+        citationLM = new InlineLayoutManager(footnote.getFootnoteCitation());
 
         // create a FootnoteBodyLM handling the fo:footnote-body child of fo:footnote
         bodyLM = new FootnoteBodyLayoutManager(footnote.getFootnoteBody());
@@ -85,12 +86,24 @@ public class FootnoteLayoutManager extends AbstractLayoutManager
     private void addAnchor(LinkedList citationList) {
         // find the last box in the sequence, and add a reference
         // to the FootnoteBodyLM
-        ListIterator citationIterator = citationList.listIterator(citationList.size());
         KnuthInlineBox lastBox = null;
+        ListIterator citationIterator = citationList.listIterator(citationList.size());
         while (citationIterator.hasPrevious() && lastBox == null) {
-            KnuthElement element = (KnuthElement) citationIterator.previous();
-            if (element instanceof KnuthInlineBox) {
-                lastBox = (KnuthInlineBox) element;
+            Object obj = citationIterator.previous();
+            if (obj instanceof KnuthElement) {
+                KnuthElement element = (KnuthElement)obj;
+                if (element instanceof KnuthInlineBox) {
+                    lastBox = (KnuthInlineBox) element;
+                }
+            } else {
+                KnuthSequence seq = (KnuthSequence)obj;
+                ListIterator nestedIterator = seq.listIterator(seq.size());
+                while (nestedIterator.hasPrevious() && lastBox == null) {
+                    KnuthElement element = (KnuthElement)nestedIterator.previous();
+                    if (element instanceof KnuthInlineBox) {
+                        lastBox = (KnuthInlineBox) element;
+                    }
+                }
             }
         }
         if (lastBox != null) {
index 7f0943a9f63583f842eabdef7b795b55b659dce3..72b8c7badee52f5016d5d72095b68d876b5f1059 100755 (executable)
@@ -21,6 +21,9 @@ package org.apache.fop.layoutmgr.inline;
 import java.util.ListIterator;
 import java.util.LinkedList;
 
+import org.apache.fop.area.Area;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.fo.flow.Inline;
 import org.apache.fop.fo.flow.InlineLevel;
@@ -28,10 +31,14 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonMarginInline;
 import org.apache.fop.fo.properties.SpaceProperty;
 import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthSequence;
+import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.SpaceSpecifier;
 import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.traits.SpaceVal;
 
@@ -46,6 +53,9 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
     private CommonMarginInline inlineProps = null;
     private CommonBorderPaddingBackground borderProps = null;
 
+    private boolean bAreaCreated = false;
+    private LayoutManager lastChildLM = null; // Set when return last breakposs;
+
     /**
      * Create an inline layout manager.
      * This is used for fo's that create areas that
@@ -109,8 +119,14 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
     }
     
     /** @see org.apache.fop.layoutmgr.inline.InlineStackingLayoutManager#createArea() */
-    protected InlineParent createArea() {
-        InlineParent area = super.createArea(); 
+    protected InlineArea createArea(boolean bInlineParent) {
+        InlineArea area;
+        if (bInlineParent) {
+            area = new InlineParent();
+            area.setOffset(0);
+        } else {
+            area = new InlineBlockParent();
+        }
         TraitSetter.setProducerID(area, getInlineFO().getId());
         return area;
     }
@@ -132,7 +148,8 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
 
     /** @see org.apache.fop.layoutmgr.LayoutManager */
     public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
-        InlineLevelLayoutManager curLM;
+        InlineLevelLayoutManager curILM;
+        LayoutManager curLM, lastLM = null;
 
         // the list returned by child LM
         LinkedList returnedList;
@@ -140,6 +157,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
 
         // the list which will be returned to the parent LM
         LinkedList returnList = new LinkedList();
+        KnuthSequence lastSequence = null;
 
         SpaceSpecifier leadingSpace = lc.getLeadingSpace();
 
@@ -160,27 +178,236 @@ public class InlineLayoutManager extends InlineStackingLayoutManager
             clearPrevIPD(); // Clear stored prev content dimensions
         }
 
-        while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
+        StringBuffer trace = new StringBuffer("InlineLM:");
+
+        while ((curLM = (LayoutManager) getChildLM()) != null) {
             // get KnuthElements from curLM
             returnedList = curLM.getNextKnuthElements(lc, alignment);
-            if (returnedList != null) {
+            if (returnedList == null) {
+                // curLM returned null because it finished;
+                // just iterate once more to see if there is another child
+                continue;
+            }
+            if (curLM instanceof InlineLevelLayoutManager) {
+                // close the last block sequence 
+                if (lastSequence != null && !lastSequence.isInlineSequence()) {
+                    lastSequence = null;
+                    if (log.isTraceEnabled()) {
+                        trace.append(" ]");
+                    }
+                }
                 // "wrap" the Position stored in each element of returnedList
-                ListIterator listIter = returnedList.listIterator();
-                while (listIter.hasNext()) {
-                    returnedElement = (KnuthElement) listIter.next();
-                    returnedElement.setPosition
+                ListIterator seqIter = returnedList.listIterator();
+                while (seqIter.hasNext()) {
+                    KnuthSequence sequence = (KnuthSequence) seqIter.next();
+                    ListIterator listIter = sequence.listIterator();
+                    while (listIter.hasNext()) {
+                        returnedElement = (KnuthElement) listIter.next();
+                        returnedElement.setPosition
                         (new NonLeafPosition(this,
-                                             returnedElement.getPosition()));
-                    returnList.add(returnedElement);
+                                returnedElement.getPosition()));
+                    }
+                    if (!sequence.isInlineSequence()) {
+                        if (lastSequence != null && lastSequence.isInlineSequence()) {
+                            // log.error("Last inline sequence should be closed before a block sequence");
+                            lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                                   false, null, false));
+                            lastSequence = null;
+                            if (log.isTraceEnabled()) {
+                                trace.append(" ]");
+                            }
+                        }
+                        returnList.add(sequence);
+                        if (log.isTraceEnabled()) {
+                            trace.append(" B");
+                        }
+                    } else {
+                        if (lastSequence == null) {
+                            lastSequence = new KnuthSequence(true);
+                            returnList.add(lastSequence);
+                            if (log.isTraceEnabled()) {
+                                trace.append(" [");
+                            }
+                        } else {
+                            if (log.isTraceEnabled()) {
+                                trace.append(" +");
+                            }
+                        }
+                        lastSequence.addAll(sequence);
+                        if (log.isTraceEnabled()) {
+                            trace.append(" I");
+                        }
+                       // finish last paragraph if it was closed with a linefeed
+                        KnuthElement lastElement = (KnuthElement) sequence.getLast();
+                        if (lastElement.isPenalty()
+                                && ((KnuthPenalty) lastElement).getP()
+                                == -KnuthPenalty.INFINITE) {
+                            // a penalty item whose value is -inf
+                            // represents a preserved linefeed,
+                            // wich forces a line break
+                            lastSequence = null;
+                            if (log.isTraceEnabled()) {
+                                trace.append(" ]");
+                            }
+                        }
+                    }
+                }
+            } else { // A block LM
+                // close the last inline sequence 
+                if (lastSequence != null && lastSequence.isInlineSequence()) {
+                    lastSequence.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                           false, null, false));
+                    lastSequence = null;
+                    if (log.isTraceEnabled()) {
+                        trace.append(" ]");
+                    }
+                }
+                if (curLM != lastLM) {
+                    // close the last block sequence
+                    if (lastSequence != null && !lastSequence.isInlineSequence()) {
+                        lastSequence = null;
+                        if (log.isTraceEnabled()) {
+                            trace.append(" ]");
+                        }
+                    }
+                    lastLM = curLM;
+                }
+                if (lastSequence == null) {
+                    lastSequence = new KnuthSequence(false);
+                    returnList.add(lastSequence);
+                    if (log.isTraceEnabled()) {
+                        trace.append(" [");
+                    }
+                } else {
+                    if (log.isTraceEnabled()) {
+                        trace.append(" +");
+                    }
+                }
+                ListIterator iter = returnedList.listIterator();
+                while (iter.hasNext()) {
+                    KnuthElement element = (KnuthElement) iter.next();
+                    element.setPosition
+                    (new NonLeafPosition(this,
+                            element.getPosition()));
+                }
+                lastSequence.addAll(returnedList);
+                if (log.isTraceEnabled()) {
+                    trace.append(" L");
                 }
-                return returnList;
-            } else {
-                // curLM returned null because it finished;
-                // just iterate once more to see if there is another child
             }
         }
         setFinished(true);
-        return null;
+        log.trace(trace);
+        return returnList.size() == 0 ? null : returnList;
+    }
+
+    /**
+     * Generate and add areas to parent area.
+     * Set size of each area. This should only create and return one
+     * inline area for any inline parent area.
+     *
+     * @param parentIter Iterator over Position information returned
+     * by this LayoutManager.
+     * @param dSpaceAdjust Factor controlling how much extra space to add
+     * in order to justify the line.
+     */
+    public void addAreas(PositionIterator parentIter,
+                         LayoutContext context) {
+        addId();
+
+        setChildContext(new LayoutContext(context)); // Store current value
+
+        // If has fence, make a new leadingSS
+        /* How to know if first area created by this LM? Keep a count and
+         * reset it if getNextBreakPoss() is called again.
+         */
+        if (hasLeadingFence(bAreaCreated)) {
+            getContext().setLeadingSpace(new SpaceSpecifier(false));
+            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+                                  true);
+        } else {
+            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
+                                  false);
+        }
+
+        if (getSpaceStart() != null) {
+            context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
+        }
+
+        // "unwrap" the NonLeafPositions stored in parentIter
+        // and put them in a new list; 
+        // also set lastLM to be the LayoutManager which created
+        // the last Position: if the LAST_AREA flag is set in context,
+        // it must be also set in the LayoutContext given to lastLM,
+        // but unset in the LayoutContext given to the other LMs
+        LinkedList positionList = new LinkedList();
+        NonLeafPosition pos = null;
+        LayoutManager lastLM = null; // last child LM in this iterator
+        while (parentIter.hasNext()) {
+            pos = (NonLeafPosition) parentIter.next();
+            positionList.add(pos.getPosition());
+        }
+        if (pos != null) {
+            lastLM = pos.getPosition().getLM();
+        }
+
+        InlineArea parent = createArea(lastLM == null || lastLM instanceof InlineLevelLayoutManager);
+        parent.setBPD(context.getLineHeight());
+        setCurrentArea(parent);
+        
+        StackingIter childPosIter
+            = new StackingIter(positionList.listIterator());
+
+        LayoutManager prevLM = null;
+        LayoutManager childLM;
+        while ((childLM = childPosIter.getNextChildLM())
+               != null) {
+            getContext().setFlags(LayoutContext.LAST_AREA,
+                                  context.isLastArea() && childLM == lastLM);
+            childLM.addAreas(childPosIter, getContext());
+            getContext().setLeadingSpace(getContext().getTrailingSpace());
+            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+            prevLM = childLM;
+        }
+
+        /* If has trailing fence,
+         * resolve trailing space specs from descendants.
+         * Otherwise, propagate any trailing space specs to parent LM via
+         * the context object.
+         * If the last child LM called return ISLAST in the context object
+         * and it is the last child LM for this LM, then this must be
+         * the last area for the current LM also.
+         */
+        boolean bIsLast =
+          (getContext().isLastArea() && prevLM == lastChildLM);
+        if (hasTrailingFence(bIsLast)) {
+            addSpace(getCurrentArea(),
+                     getContext().getTrailingSpace().resolve(false),
+                     getContext().getSpaceAdjust());
+            context.setTrailingSpace(new SpaceSpecifier(false));
+        } else {
+            // Propagate trailing space-spec sequence to parent LM in context
+            context.setTrailingSpace(getContext().getTrailingSpace());
+        }
+        // Add own trailing space to parent context (or set on area?)
+        if (context.getTrailingSpace() != null  && getSpaceEnd() != null) {
+            context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
+        }
+        setTraits(bAreaCreated, !bIsLast);
+        
+        parentLM.addChildArea(getCurrentArea());
+        context.setFlags(LayoutContext.LAST_AREA, bIsLast);
+        bAreaCreated = true;
+    }
+
+    public void addChildArea(Area childArea) {
+        Area parent = getCurrentArea();
+        if (getContext().resolveLeadingSpace()) {
+            addSpace(parent,
+                    getContext().getLeadingSpace().resolve(false),
+                    getContext().getSpaceAdjust());
+        }
+        parent.addChildArea(childArea);
     }
 
     /*
index 0b05cc8aae6d5521b5b3267aef58fc019436aaff..eb8eab71770d1e4143371066c3f685d547adb622 100644 (file)
@@ -33,11 +33,7 @@ import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.PositionIterator;
-import org.apache.fop.layoutmgr.SpaceSpecifier;
-import org.apache.fop.traits.SpaceVal;
 import org.apache.fop.area.Area;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.Space;
 import org.apache.fop.traits.MinOptMax;
 
@@ -50,7 +46,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
                                          implements InlineLevelLayoutManager {
 
 
-    private static class StackingIter extends PositionIterator {
+    protected static class StackingIter extends PositionIterator {
 
         StackingIter(Iterator parentIter) {
             super(parentIter);
@@ -81,7 +77,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
     //private BreakPoss prevBP;
     protected LayoutContext childLC;
 
-    private LayoutManager lastChildLM = null; // Set when return last breakposs
     private boolean bAreaCreated = false;
 
     //private LayoutManager currentLM = null;
@@ -177,10 +172,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
         hmPrevIPD.clear();
     }
 
-    protected InlineParent createArea() {
-        return new InlineParent();
-    }
-
     /**
      * This method is called by addAreas() so IDs can be added to a page for FOs that 
      * support the 'id' property.
@@ -189,103 +180,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
         // Do nothing here, overriden in subclasses that have an 'id' property.
     }
     
-    /**
-     * Generate and add areas to parent area.
-     * Set size of each area. This should only create and return one
-     * inline area for any inline parent area.
-     *
-     * @param parentIter Iterator over Position information returned
-     * by this LayoutManager.
-     * @param dSpaceAdjust Factor controlling how much extra space to add
-     * in order to justify the line.
-     */
-    public void addAreas(PositionIterator parentIter,
-                         LayoutContext context) {
-        addId();
-        InlineParent parent = createArea();
-        parent.setBPD(context.getLineHeight());
-        parent.setOffset(0);
-        setCurrentArea(parent);
-
-        setChildContext(new LayoutContext(context)); // Store current value
-
-        // If has fence, make a new leadingSS
-        /* How to know if first area created by this LM? Keep a count and
-         * reset it if getNextBreakPoss() is called again.
-         */
-        if (hasLeadingFence(bAreaCreated)) {
-            getContext().setLeadingSpace(new SpaceSpecifier(false));
-            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
-                                  true);
-        } else {
-            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE,
-                                  false);
-        }
-
-        if (getSpaceStart() != null) {
-            context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
-        }
-
-        // "unwrap" the NonLeafPositions stored in parentIter
-        // and put them in a new list; 
-        // also set lastLM to be the LayoutManager which created
-        // the last Position: if the LAST_AREA flag is set in context,
-        // it must be also set in the LayoutContext given to lastLM,
-        // but unset in the LayoutContext given to the other LMs
-        LinkedList positionList = new LinkedList();
-        NonLeafPosition pos;
-        LayoutManager lastLM = null; // last child LM in this iterator
-        while (parentIter.hasNext()) {
-            pos = (NonLeafPosition) parentIter.next();
-            lastLM = pos.getPosition().getLM();
-            positionList.add(pos.getPosition());
-        }
-
-        StackingIter childPosIter
-            = new StackingIter(positionList.listIterator());
-
-        LayoutManager prevLM = null;
-        InlineLevelLayoutManager childLM;
-        while ((childLM = (InlineLevelLayoutManager) childPosIter.getNextChildLM())
-               != null) {
-            getContext().setFlags(LayoutContext.LAST_AREA,
-                                  context.isLastArea() && childLM == lastLM);
-            childLM.addAreas(childPosIter, getContext());
-            getContext().setLeadingSpace(getContext().getTrailingSpace());
-            getContext().setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
-            prevLM = childLM;
-        }
-
-        /* If has trailing fence,
-         * resolve trailing space specs from descendants.
-         * Otherwise, propagate any trailing space specs to parent LM via
-         * the context object.
-         * If the last child LM called return ISLAST in the context object
-         * and it is the last child LM for this LM, then this must be
-         * the last area for the current LM also.
-         */
-        boolean bIsLast =
-          (getContext().isLastArea() && prevLM == lastChildLM);
-        if (hasTrailingFence(bIsLast)) {
-            addSpace(getCurrentArea(),
-                     getContext().getTrailingSpace().resolve(false),
-                     getContext().getSpaceAdjust());
-            context.setTrailingSpace(new SpaceSpecifier(false));
-        } else {
-            // Propagate trailing space-spec sequence to parent LM in context
-            context.setTrailingSpace(getContext().getTrailingSpace());
-        }
-        // Add own trailing space to parent context (or set on area?)
-        if (context.getTrailingSpace() != null  && getSpaceEnd() != null) {
-            context.getTrailingSpace().addSpace(new SpaceVal(getSpaceEnd()));
-        }
-        setTraits(bAreaCreated, !bIsLast);
-        
-        parentLM.addChildArea(getCurrentArea());
-        context.setFlags(LayoutContext.LAST_AREA, bIsLast);
-        bAreaCreated = true;
-    }
-
     protected Area getCurrentArea() {
         return currentArea;
     }
@@ -298,19 +192,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
         
     }
 
-    public void addChildArea(Area childArea) {
-        // Make sure childArea is inline area
-        if (childArea instanceof InlineArea) {
-            Area parent = getCurrentArea();
-            if (getContext().resolveLeadingSpace()) {
-                addSpace(parent,
-                         getContext().getLeadingSpace().resolve(false),
-                         getContext().getSpaceAdjust());
-            }
-            parent.addChildArea(childArea);
-        }
-    }
-
     protected void setChildContext(LayoutContext lc) {
         childLC = lc;
     }
@@ -342,57 +223,6 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
         }
     }
 
-    public LinkedList getNextKnuthElements(LayoutContext lc, int alignment) {
-        InlineLevelLayoutManager curLM;
-
-        // the list returned by child LM
-        LinkedList returnedList;
-        KnuthElement returnedElement;
-
-        // the list which will be returned to the parent LM
-        LinkedList returnList = new LinkedList();
-
-        SpaceSpecifier leadingSpace = lc.getLeadingSpace();
-
-        if (lc.startsNewArea()) {
-            // First call to this LM in new parent "area", but this may
-            // not be the first area created by this inline
-            childLC = new LayoutContext(lc);
-            lc.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart()));
-
-            // Check for "fence"
-            if (hasLeadingFence(!lc.isFirstArea())) {
-                // Reset leading space sequence for child areas
-                leadingSpace = new SpaceSpecifier(false);
-            }
-            // Reset state variables
-            clearPrevIPD(); // Clear stored prev content dimensions
-        }
-
-        while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
-            // get KnuthElements from curLM
-            returnedList = curLM.getNextKnuthElements(lc, alignment);
-            if (returnedList != null) {
-                // "wrap" the Position stored in each element of returnedList
-                ListIterator listIter = returnedList.listIterator();
-                while (listIter.hasNext()) {
-                    returnedElement = (KnuthElement) listIter.next();
-                    returnedElement.setPosition
-                        (new NonLeafPosition(this,
-                                             returnedElement.getPosition()));
-                    returnList.add(returnedElement);
-                }
-                setFinished(curLM.isFinished() && (getChildLM() == null));
-                return returnList;
-            } else {
-                // curLM returned null because it finished;
-                // just iterate once more to see if there is another child
-            }
-        }
-        setFinished(true);
-        return null;
-    }
-
     public List addALetterSpaceTo(List oldList) {
         // old list contains only a box, or the sequence: box penalty glue box
 
@@ -407,7 +237,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
         oldList = ((InlineLevelLayoutManager)
                    element.getLayoutManager()).addALetterSpaceTo(oldList);
 
-        // "wrap" againg the Position stored in each element of oldList
+        // "wrap" again the Position stored in each element of oldList
         oldListIterator = oldList.listIterator();
         while (oldListIterator.hasNext()) {
             element = (KnuthElement) oldListIterator.next();
index c3091d66c7dffbfa04c5f41165a92ae38c6bf099..f51e6af2b386876d20bd0dd1e86f55f00ee06e0e 100644 (file)
@@ -37,10 +37,13 @@ import org.apache.fop.layoutmgr.KnuthSequence;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.area.Area;
 import org.apache.fop.area.LineArea;
+import org.apache.fop.area.inline.InlineArea;
 
 import java.util.ListIterator;
 import java.util.List;
@@ -184,7 +187,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
 
         public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
                          int indent) {
-            super();
+            super(true);
             layoutManager = llm;
             textAlignment = alignment;
             textAlignmentLast = alignmentLast;
@@ -268,6 +271,40 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             }
         }
 
+        private void addALetterSpace() {
+            KnuthBox prevBox = (KnuthBox) removeLast();
+            LinkedList oldList = new LinkedList();
+            // if there are two consecutive KnuthBoxes the
+            // first one does not represent a whole word,
+            // so it must be given one more letter space
+            if (!prevBox.isAuxiliary()) {
+                // if letter spacing is constant,
+                // only prevBox needs to be replaced;
+                oldList.add(prevBox);
+            } else {
+                // prevBox is the last element
+                // in the sub-sequence
+                //   <box> <aux penalty> <aux glue> <aux box>
+                // the letter space is added to <aux glue>,
+                // while the other elements are not changed
+                oldList.add(prevBox);
+                oldList.addFirst((KnuthGlue) removeLast());
+                oldList.addFirst((KnuthPenalty) removeLast());
+                oldList.addFirst((KnuthBox) removeLast());
+            }
+            // adding a letter space could involve, according to the text
+            // represented by oldList, replacing a glue element or adding
+            // new elements
+            addAll(((InlineLevelLayoutManager)
+                         prevBox.getLayoutManager())
+                        .addALetterSpaceTo(oldList));
+            if (((KnuthInlineBox) prevBox).isAnchor()) {
+                // prevBox represents a footnote citation: copy footnote info
+                // from prevBox to the new box
+                KnuthInlineBox newBox = (KnuthInlineBox) getLast();
+                newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+            }
+        }
     }
 
     private class LineBreakingAlgorithm extends BreakingAlgorithm {
@@ -510,6 +547,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         initialize(); // Normally done when started by parent!
     }
 
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         // Get a break from currently active child LM
         // Set up constraints for inline level managers
@@ -546,7 +584,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         }
 
         //PHASE 2: Create line breaks
-        return findOptimalLineBreakingPoints(alignment);
+        return createLineBreaks(context.getBPAlignment());
         /*
         LineBreakPosition lbp = null;
         if (breakpoints == null) {
@@ -586,19 +624,17 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         LayoutContext inlineLC = new LayoutContext(context);
 
         InlineLevelLayoutManager curLM;
-        KnuthElement thisElement = null;
         LinkedList returnedList = null;
         iLineWidth = context.getStackLimit().opt;
 
         // convert all the text in a sequence of paragraphs made
         // of KnuthBox, KnuthGlue and KnuthPenalty objects
         boolean bPrevWasKnuthBox = false;
-        KnuthBox prevBox = null;
 
-        Paragraph knuthPar = new Paragraph(this, 
-                                           bTextAlignment, bTextAlignmentLast, 
-                                           textIndent.getValue());
-        knuthPar.startParagraph(availIPD.opt);
+        StringBuffer trace = new StringBuffer("LineLM:");
+
+        Paragraph lastPar = null;
+
         while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
             if ((returnedList
                  = curLM.getNextKnuthElements(inlineLC,
@@ -607,78 +643,119 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 if (returnedList.size() == 0) {
                     continue;
                 }
-                // look at the first element
-                thisElement = (KnuthElement) returnedList.getFirst();
-                if (thisElement.isBox() && !thisElement.isAuxiliary()
-                    && bPrevWasKnuthBox) {
-                    prevBox = (KnuthBox) knuthPar.removeLast();
-                    LinkedList oldList = new LinkedList();
-                    // if there are two consecutive KnuthBoxes the
-                    // first one does not represent a whole word,
-                    // so it must be given one more letter space
-                    if (!prevBox.isAuxiliary()) {
-                        // if letter spacing is constant,
-                        // only prevBox needs to be replaced;
-                        oldList.add(prevBox);
+                // does the first element of the first paragraph add to an existing word?
+                if (lastPar != null) {
+                    Object obj = returnedList.getFirst();
+                    KnuthElement thisElement;
+                    if (obj instanceof KnuthElement) {
+                        thisElement = (KnuthElement)obj;
                     } else {
-                        // prevBox is the last element
-                        // in the sub-sequence
-                        //   <box> <aux penalty> <aux glue> <aux box>
-                        // the letter space is added to <aux glue>,
-                        // while the other elements are not changed
-                        oldList.add(prevBox);
-                        oldList.addFirst((KnuthGlue) knuthPar.removeLast());
-                        oldList.addFirst((KnuthPenalty) knuthPar.removeLast());
-                        oldList.addFirst((KnuthBox) knuthPar.removeLast());
+                        KnuthSequence firstSeq = (KnuthSequence) obj;
+                        if (!firstSeq.isInlineSequence()) {
+                            log.error("Expect inline sequence as first sequence when last paragraph is not null");
+                        }
+                        thisElement = (KnuthElement) firstSeq.get(0);
                     }
-                    // adding a letter space could involve, according to the text
-                    // represented by oldList, replacing a glue element or adding
-                    // new elements
-                    knuthPar.addAll(((InlineLevelLayoutManager)
-                                     prevBox.getLayoutManager())
-                                    .addALetterSpaceTo(oldList));
-                    if (((KnuthInlineBox) prevBox).isAnchor()) {
-                        // prevBox represents a footnote citation: copy footnote info
-                        // from prevBox to the new box
-                        KnuthInlineBox newBox = (KnuthInlineBox) knuthPar.getLast();
-                        newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+                    if (thisElement.isBox() && !thisElement.isAuxiliary()
+                            && bPrevWasKnuthBox) {
+                        lastPar.addALetterSpace();
                     }
                 }
 
-                // look at the last element
-                KnuthElement lastElement = (KnuthElement) returnedList.getLast();
-                boolean bForceLinefeed = false;
-                if (lastElement.isBox()) {
-                    bPrevWasKnuthBox = true;
-                } else {
-                    bPrevWasKnuthBox = false;
-                    if (lastElement.isPenalty()
-                        && ((KnuthPenalty) lastElement).getP()
-                            == -KnuthPenalty.INFINITE) {
-                        // a penalty item whose value is -inf
-                        // represents a preserved linefeed,
-                        // wich forces a line break
-                        bForceLinefeed = true;
-                        returnedList.removeLast();
+                // loop over the KnuthSequences (and single KnuthElements) in returnedList
+                // (LeafNodeLM descendants may also skip wrapping elements in KnuthSequences
+                // to cause fewer container structures)
+                // TODO the mixture here adds a little to the complexity. Decide whether:
+                // - to leave as is and save some container instances
+                // - to use KnuthSequences exclusively (adjustments on leaf-type LMs necessary)
+                // See also FootnoteLM.addAnchor() as well as right above this comment
+                // for similar code. Or see http://svn.apache.org/viewcvs?rev=230779&view=rev 
+                ListIterator iter = returnedList.listIterator();
+                while (iter.hasNext()) {
+                    Object obj = iter.next();
+                    KnuthElement singleElement = null;
+                    KnuthSequence sequence = null;
+                    if (obj instanceof KnuthElement) {
+                        singleElement = (KnuthElement)obj;
+                    } else {
+                        sequence = (KnuthSequence)obj;
                     }
-                }
+                    // the sequence contains inline Knuth elements
+                    if (singleElement != null || sequence.isInlineSequence()) {
+                        // look at the last element 
+                        KnuthElement lastElement;
+                        if (singleElement != null) {
+                            lastElement = singleElement;
+                        } else {
+                            lastElement = (KnuthElement) sequence.getLast();
+                            if (lastElement == null) {
+                                throw new NullPointerException(
+                                        "Sequence was empty! lastElement is null");
+                            }
+                        }
+                        bPrevWasKnuthBox = lastElement.isBox();
+
+                        // if last paragraph is open, add the new elements to the paragraph
+                        // else this is the last paragraph
+                        if (lastPar == null) { 
+                            lastPar = new Paragraph(this, 
+                                                    bTextAlignment, bTextAlignmentLast, 
+                                                    textIndent.getValue());
+                            lastPar.startParagraph(availIPD.opt);
+                            if (log.isTraceEnabled()) {
+                                trace.append(" [");
+                            }
+                        } else {
+                            if (log.isTraceEnabled()) {
+                                trace.append(" +");
+                            }
+                        }
+                        if (singleElement != null) {
+                            lastPar.add(singleElement);
+                        } else {
+                            lastPar.addAll(sequence);
+                        }
+                        if (log.isTraceEnabled()) {
+                            trace.append(" I");
+                        }
 
-                // add the new elements to the paragraph
-                knuthPar.addAll(returnedList);
-                if (bForceLinefeed) {
-                    if (knuthPar.size() == 0) {
-                        //only a forced linefeed on this line 
-                        //-> compensate with a zero width box
-                        knuthPar.add(new KnuthInlineBox(0, 0, 0, 0,
-                                null, false));
+                        // finish last paragraph if it was closed with a linefeed
+                        if (lastElement.isPenalty()
+                                && ((KnuthPenalty) lastElement).getP()
+                                    == -KnuthPenalty.INFINITE) {
+                            // a penalty item whose value is -inf
+                            // represents a preserved linefeed,
+                            // wich forces a line break
+                            lastPar.removeLast();
+                            if (lastPar.size() == 0) {
+                                //only a forced linefeed on this line 
+                                //-> compensate with a zero width box
+                                lastPar.add(new KnuthInlineBox(0, 0, 0, 0,
+                                        null, false));
+                            }
+                            lastPar.endParagraph();
+                            ElementListObserver.observe(lastPar, "line", null);
+                            lastPar = null;
+                            if (log.isTraceEnabled()) {
+                                trace.append(" ]");
+                            }
+                            bPrevWasKnuthBox = false;
+                        }
+                    } else { // the sequence is a block sequence
+/*                        // "wrap" the Position stored in each element of returnedList
+                        ListIterator listIter = sequence.listIterator();
+                        while (listIter.hasNext()) {
+                            KnuthElement returnedElement = (KnuthElement) listIter.next();
+                            returnedElement.setPosition
+                                (new NonLeafPosition(this,
+                                                     returnedElement.getPosition()));
+                        }
+*/                        knuthParagraphs.add(sequence);
+                        if (log.isTraceEnabled()) {
+                            trace.append(" B");
+                        }
                     }
-                    knuthPar.endParagraph();
-                    knuthPar = new Paragraph(this, 
-                                             bTextAlignment, bTextAlignmentLast, 
-                                             textIndent.getValue());
-                    knuthPar.startParagraph(availIPD.opt);
-                    bPrevWasKnuthBox = false;
-                }
+                } // end of loop over returnedList
             } else {
                 // curLM returned null; this can happen
                 // if it has nothing more to layout,
@@ -686,8 +763,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 // if there are other children
             }
         }
-        knuthPar.endParagraph();
-        ElementListObserver.observe(knuthPar, "line", null);
+        if (lastPar != null) {
+            lastPar.endParagraph();
+            ElementListObserver.observe(lastPar, "line", null);
+            if (log.isTraceEnabled()) {
+                trace.append(" ]");
+            }
+        }
+        log.trace(trace);
     }
 
     /**
@@ -822,121 +905,167 @@ public class LineLayoutManager extends InlineStackingLayoutManager
     
     /**
      * Phase 2 of Knuth algorithm: find optimal break points.
-     * @param alignment alignmenr of the paragraph
+     * @param alignment alignment in BP direction of the paragraph
      * @return a list of Knuth elements representing broken lines
      */
-    private LinkedList findOptimalLineBreakingPoints(int alignment) {
+    private LinkedList createLineBreaks(int alignment) {
 
         // find the optimal line breaking points for each paragraph
         ListIterator paragraphsIterator
             = knuthParagraphs.listIterator(knuthParagraphs.size());
-        Paragraph currPar = null;
-        LineBreakingAlgorithm alg;
         lineLayoutsList = new ArrayList(knuthParagraphs.size());
         while (paragraphsIterator.hasPrevious()) {
-            lineLayouts = new LineLayoutPossibilities();
-            currPar = (Paragraph) paragraphsIterator.previous();
-            double maxAdjustment = 1;
-            int iBPcount = 0;
-            alg = new LineBreakingAlgorithm(alignment,
-                                            bTextAlignment, bTextAlignmentLast,
-                                            textIndent.getValue(), currPar.lineFiller.opt,
-                                            lineHeight, lead, follow, middleShift,
-                                            (knuthParagraphs.indexOf(currPar) == 0),
-                                            this);
-    
-            if (hyphProps.hyphenate == EN_TRUE) {
-                findHyphenationPoints(currPar);
-            }
-    
-            // first try
-            boolean bHyphenationAllowed = false;
-            alg.setConstantLineWidth(iLineWidth);
-            iBPcount = alg.findBreakingPoints(currPar,
-                                              maxAdjustment, false, bHyphenationAllowed);
-            if (iBPcount == 0 || alignment == EN_JUSTIFY) {
-                // if the first try found a set of breaking points, save them
-                if (iBPcount > 0) {
-                    alg.resetAlgorithm();
-                    lineLayouts.savePossibilities(false);
-                } else {
-                    // the first try failed
-                    log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
-                }
-    
-                // now try something different
-                log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
-                if (hyphProps.hyphenate == EN_TRUE) {
-                    // consider every hyphenation point as a legal break
-                    bHyphenationAllowed = true;
-                } else {
-                    // try with a higher threshold
-                    maxAdjustment = 5;
-                }
-    
-                if ((iBPcount
-                     = alg.findBreakingPoints(currPar,
-                                              maxAdjustment, false, bHyphenationAllowed)) == 0) {
-                    // the second try failed too, try with a huge threshold
-                    // and force the algorithm to find
-                    // a set of breaking points
-                    log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
-                                     + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
-                    maxAdjustment = 20;
-                    iBPcount
-                        = alg.findBreakingPoints(currPar,
-                                                 maxAdjustment, true, bHyphenationAllowed);
-                }
-    
-                // use non-hyphenated breaks, when possible
-                lineLayouts.restorePossibilities();
-    
-                /* extension (not in the XSL FO recommendation): if vertical alignment
-                   is justify and the paragraph has only one layout, try using 
-                   shorter or longer lines */
-                //TODO This code snippet is disabled. Reenable?
-                if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
-                    //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
-                    //System.out.println("                          layouts with fewer lines? " + lineLayouts.canUseLessLines());
-                    if (!lineLayouts.canUseMoreLines()) {
-                        alg.resetAlgorithm();
-                        lineLayouts.savePossibilities(true);
-                        // try with shorter lines
-                        int savedLineWidth = iLineWidth;
-                        iLineWidth = (int) (iLineWidth * 0.95);
-                        iBPcount = alg.findBreakingPoints(currPar,
-                                 maxAdjustment, true, bHyphenationAllowed);
-                        // use normal lines, when possible
-                        lineLayouts.restorePossibilities();
-                        iLineWidth = savedLineWidth;
-                    }
-                    if (!lineLayouts.canUseLessLines()) {
-                        alg.resetAlgorithm();
-                        lineLayouts.savePossibilities(true);
-                        // try with longer lines
-                        int savedLineWidth = iLineWidth;
-                        iLineWidth = (int) (iLineWidth * 1.05);
-                        alg.setConstantLineWidth(iLineWidth);
-                        iBPcount = alg.findBreakingPoints(currPar,
-                                maxAdjustment, true, bHyphenationAllowed);
-                        // use normal lines, when possible
-                        lineLayouts.restorePossibilities();
-                        iLineWidth = savedLineWidth;
-                    }
-                    //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
-                    //System.out.println("                          now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
-                }
+            KnuthSequence seq = (KnuthSequence) paragraphsIterator.previous();
+            if (!seq.isInlineSequence()) {
+                lineLayouts = createBlockLineBreak(seq);
+            } else {
+                lineLayouts = findOptimalBreakingPoints(alignment, (Paragraph) seq);
             }
             lineLayoutsList.add(0, lineLayouts);
         }
         
-        
         setFinished(true);
     
         //Post-process the line breaks found
         return postProcessLineBreaks(alignment);
     }
 
+    /**
+     * create a single line layout possibility with a single linebreak
+     * for a block sequence
+     * @param seq the Knuth sequence for which the linebreak is created
+     * @return the line layout possibilities for the paragraph
+     */
+    private LineLayoutPossibilities createBlockLineBreak(KnuthSequence seq) {
+        //TODO Should this really create only a single LineBreakPosition???
+        //This creates an implicit keep-together on the nested block-level FOs.
+        lineLayouts = new LineLayoutPossibilities();
+        lineLayouts.addPossibility(1,0);
+        int lineHeight = 0, lineStretch = 0, lineShrink = 0;
+        ListIterator seqIterator = seq.listIterator();
+        while (seqIterator.hasNext()) {
+            KnuthElement element = (KnuthElement) seqIterator.next();
+            lineHeight += element.getW();
+            if (element.isGlue()) {
+                lineStretch += element.getY();
+                lineShrink += element.getZ();
+            }
+        }
+        LineBreakPosition lbp = new LineBreakPosition(this,
+                knuthParagraphs.indexOf(seq), seq.size() - 1,
+                lineShrink, lineStretch, 0, 0, 0, 0, lineHeight,
+                iLineWidth, 0, 0, 0);
+        lineLayouts.addBreakPosition(lbp, 0);
+        return lineLayouts;
+    }
+
+    /**
+     * Fint the optimal linebreaks for a paragraph
+     * @param alignment alignment of the paragraph
+     * @param currPar the Paragraph for which the linebreaks are found
+     * @return the line layout possibilities for the paragraph
+     */
+    private LineLayoutPossibilities findOptimalBreakingPoints(int alignment, Paragraph currPar) {
+        lineLayouts = new LineLayoutPossibilities();
+        double maxAdjustment = 1;
+        int iBPcount = 0;
+        LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment,
+                bTextAlignment, bTextAlignmentLast,
+                                        textIndent.getValue(), currPar.lineFiller.opt,
+                                        lineHeight, lead, follow, middleShift,
+                                        (knuthParagraphs.indexOf(currPar) == 0),
+                                        this);
+   
+        if (hyphProps.hyphenate == EN_TRUE) {
+            findHyphenationPoints(currPar);
+        }
+   
+        // first try
+        boolean bHyphenationAllowed = false;
+        alg.setConstantLineWidth(iLineWidth);
+        iBPcount = alg.findBreakingPoints(currPar,
+                                          maxAdjustment, false, bHyphenationAllowed);
+        if (iBPcount == 0 || alignment == EN_JUSTIFY) {
+            // if the first try found a set of breaking points, save them
+            if (iBPcount > 0) {
+                alg.resetAlgorithm();
+                lineLayouts.savePossibilities(false);
+            } else {
+                // the first try failed
+                log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
+            }
+   
+            // now try something different
+            log.debug("Hyphenation possible? " + (hyphProps.hyphenate == EN_TRUE));
+            if (hyphProps.hyphenate == EN_TRUE) {
+                // consider every hyphenation point as a legal break
+                bHyphenationAllowed = true;
+            } else {
+                // try with a higher threshold
+                maxAdjustment = 5;
+            }
+   
+            if ((iBPcount
+                 = alg.findBreakingPoints(currPar,
+                                          maxAdjustment, false, bHyphenationAllowed)) == 0) {
+                // the second try failed too, try with a huge threshold
+                // and force the algorithm to find
+                // a set of breaking points
+                log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+                                 + (hyphProps.hyphenate == EN_TRUE ? " and hyphenation" : ""));
+                maxAdjustment = 20;
+                iBPcount
+                    = alg.findBreakingPoints(currPar,
+                                             maxAdjustment, true, bHyphenationAllowed);
+            }
+   
+            // use non-hyphenated breaks, when possible
+            lineLayouts.restorePossibilities();
+   
+            /* extension (not in the XSL FO recommendation): if vertical alignment
+               is justify and the paragraph has only one layout, try using 
+               shorter or longer lines */
+            //TODO This code snippet is disabled. Reenable?
+            if (false && alignment == EN_JUSTIFY && bTextAlignment == EN_JUSTIFY) {
+                //System.out.println("LLM.getNextKnuthElements> layouts with more lines? " + lineLayouts.canUseMoreLines());
+                //System.out.println("                          layouts with fewer lines? " + lineLayouts.canUseLessLines());
+                if (!lineLayouts.canUseMoreLines()) {
+                    alg.resetAlgorithm();
+                    lineLayouts.savePossibilities(true);
+                    // try with shorter lines
+                    int savedLineWidth = iLineWidth;
+                    iLineWidth = (int) (iLineWidth * 0.95);
+                    iBPcount = alg.findBreakingPoints(currPar,
+                             maxAdjustment, true, bHyphenationAllowed);
+                    // use normal lines, when possible
+                    lineLayouts.restorePossibilities();
+                    iLineWidth = savedLineWidth;
+                }
+                if (!lineLayouts.canUseLessLines()) {
+                    alg.resetAlgorithm();
+                    lineLayouts.savePossibilities(true);
+                    // try with longer lines
+                    int savedLineWidth = iLineWidth;
+                    iLineWidth = (int) (iLineWidth * 1.05);
+                    alg.setConstantLineWidth(iLineWidth);
+                    iBPcount = alg.findBreakingPoints(currPar,
+                            maxAdjustment, true, bHyphenationAllowed);
+                    // use normal lines, when possible
+                    lineLayouts.restorePossibilities();
+                    iLineWidth = savedLineWidth;
+                }
+                //System.out.println("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
+                //System.out.println("                          now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
+            }
+        }
+        return lineLayouts;
+    }
+
+    /**
+     * Creates the element list in BP direction for the broken lines.
+     * @param alignment the currently applicable vertical alignment
+     * @return the newly built element list
+     */
     private LinkedList postProcessLineBreaks(int alignment) {
     
         LinkedList returnList = new LinkedList();
@@ -949,8 +1078,22 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             }
         
             lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
-        
-            if (alignment == EN_JUSTIFY) {
+            KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(p);
+
+            if (!seq.isInlineSequence()) {
+                LinkedList targetList = new LinkedList();
+                ListIterator listIter = seq.listIterator();
+                while (listIter.hasNext()) {
+                    KnuthElement tempElement;
+                    tempElement = (KnuthElement) listIter.next();
+                    if (tempElement.getLayoutManager() != this) {
+                        tempElement.setPosition(new NonLeafPosition(this,
+                                tempElement.getPosition()));
+                    }
+                    targetList.add(tempElement);
+                }
+                returnList.addAll(targetList); 
+            } else if (seq.isInlineSequence() && alignment == EN_JUSTIFY) {
                 /* justified vertical alignment (not in the XSL FO recommendation):
                    create a multi-layout sequence whose elements will contain 
                    a conventional Position */
@@ -975,17 +1118,28 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                     // create a list of the FootnoteBodyLM handling footnotes 
                     // whose citations are in this line
                     LinkedList footnoteList = new LinkedList();
-                    ListIterator elementIterator = ((Paragraph) knuthParagraphs.get(p)).listIterator(startIndex);
+                    ListIterator elementIterator = seq.listIterator(startIndex);
                     while (elementIterator.nextIndex() <= endIndex) {
                         KnuthElement element = (KnuthElement) elementIterator.next();
                         if (element instanceof KnuthInlineBox
                             && ((KnuthInlineBox) element).isAnchor()) {
                             footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
+                        } else if (element instanceof KnuthBlockBox) {
+                            footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
                         }
                     }
                     startIndex = endIndex + 1;
-                    returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
-                                                     footnoteList, lineLayouts.getChosenPosition(i), false));
+                    LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
+                    returnList.add(new KnuthBlockBox(lbp.lineHeight, footnoteList, lbp, false));
+                    /* // add stretch and shrink to the returnlist
+                    if (!seq.isInlineSequence()
+                            && lbp.availableStretch != 0 || lbp.availableShrink != 0) {
+                        returnList.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                false, new Position(this), false));
+                        returnList.add(new KnuthGlue(0, lbp.availableStretch, lbp.availableShrink,
+                                new Position(this), false));
+                    }
+                    */
                 }
             }
         }
@@ -1403,7 +1557,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         while (parentIter.hasNext()) {
             Position pos = (Position) parentIter.next();
             if (pos instanceof LineBreakPosition) {
-                ListIterator paragraphIterator = null;
+                ListIterator seqIterator = null;
                 KnuthElement tempElement = null;
                 // the TLM which created the last KnuthElement in this line
                 LayoutManager lastLM = null;
@@ -1412,6 +1566,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 LineArea lineArea = new LineArea();
                 lineArea.setStartIndent(lbp.startIndent);
                 lineArea.setBPD(lbp.lineHeight);
+                lineArea.setIPD(lbp.lineWidth);
                 lc.setBaseline(lbp.baseline);
                 lc.setLineHeight(lbp.lineHeight);
                 lc.setMiddleShift(middleShift);
@@ -1419,43 +1574,46 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 lc.setBottomShift(lbp.bottomShift);
 
                 iCurrParIndex = lbp.iParIndex;
-                Paragraph currPar = (Paragraph) knuthParagraphs.get(iCurrParIndex);
+                KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex); 
                 iEndElement = lbp.getLeafPos();
     
-                // ignore the first elements added by the LineLayoutManager
-                iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-    
-                // ignore the last elements added by the LineLayoutManager
-                iEndElement -= (iEndElement == (currPar.size() - 1))
+                if (seq instanceof Paragraph) {
+                    Paragraph currPar = (Paragraph) seq;
+                    // ignore the first elements added by the LineLayoutManager
+                    iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
+                    
+                    // ignore the last elements added by the LineLayoutManager
+                    iEndElement -= (iEndElement == (currPar.size() - 1))
                     ? currPar.ignoreAtEnd : 0;
-    
+                }
+                
                 // ignore the last element in the line if it is a KnuthGlue object
-                paragraphIterator = currPar.listIterator(iEndElement);
-                tempElement = (KnuthElement) paragraphIterator.next();
+                seqIterator = seq.listIterator(iEndElement);
+                tempElement = (KnuthElement) seqIterator.next();
                 if (tempElement.isGlue()) {
                     iEndElement --;
                     // this returns the same KnuthElement
-                    paragraphIterator.previous();
-                    tempElement = (KnuthElement) paragraphIterator.previous();
+                    seqIterator.previous();
+                    tempElement = (KnuthElement) seqIterator.previous();
                 }
                 lastLM = tempElement.getLayoutManager();
     
                 // ignore KnuthGlue and KnuthPenalty objects
                 // at the beginning of the line
-                paragraphIterator = currPar.listIterator(iStartElement);
-                tempElement = (KnuthElement) paragraphIterator.next();
-                while (!tempElement.isBox() && paragraphIterator.hasNext()) {
-                    tempElement = (KnuthElement) paragraphIterator.next();
+                seqIterator = seq.listIterator(iStartElement);
+                tempElement = (KnuthElement) seqIterator.next();
+                while (!tempElement.isBox() && seqIterator.hasNext()) {
+                    tempElement = (KnuthElement) seqIterator.next();
                     iStartElement ++;
                 }
     
                 // Add the inline areas to lineArea
                 PositionIterator inlinePosIter
-                    = new KnuthPossPosIter(currPar, iStartElement,
+                    = new KnuthPossPosIter(seq, iStartElement,
                                            iEndElement + 1);
     
                 iStartElement = lbp.getLeafPos() + 1;
-                if (iStartElement == currPar.size()) {
+                if (iStartElement == seq.size()) {
                     // advance to next paragraph
                     iStartElement = 0;
                 }
@@ -1507,11 +1665,73 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                     lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
                 }
                 parentLM.addChildArea(lineArea);
+            } else if (pos instanceof NonLeafPosition) {
+                // Nested block-level content;
+                // go down the LM stack again;
+                // collect all consecutive NonLeafPosition objects,
+                // "unwrap" them and put the child positions in a new list.
+                LinkedList positionList = new LinkedList();
+                Position innerPosition;
+                innerPosition = ((NonLeafPosition) pos).getPosition();
+                positionList.add(innerPosition);
+                while (parentIter.hasNext()) {
+                    pos = (Position)parentIter.peekNext();
+                    if (!(pos instanceof NonLeafPosition)) {
+                        break;
+                    }
+                    pos = (Position) parentIter.next();
+                    innerPosition = ((NonLeafPosition) pos).getPosition();
+                    positionList.add(innerPosition);
+                }
+                
+                // do we have the last LM?
+                LayoutManager lastLM = null;
+                if (!parentIter.hasNext()) {
+                    lastLM = innerPosition.getLM();
+                }
+
+                // this may be wrong; not all areas belong inside a single line area
+                // see InlineStackingLM.addChildArea
+                LineArea lineArea = new LineArea();
+                setCurrentArea(lineArea);
+                setChildContext(lc);
+
+                PositionIterator childPosIter = new StackingIter(positionList.listIterator());
+                LayoutContext blocklc = new LayoutContext(0);
+                blocklc.setLeadingSpace(new SpaceSpecifier(true));
+                blocklc.setTrailingSpace(new SpaceSpecifier(false));
+                blocklc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+                while ((childLM = childPosIter.getNextChildLM()) != null) {
+                    // set last area flag
+                    blocklc.setFlags(LayoutContext.LAST_AREA,
+                            (context.isLastArea() && childLM == lastLM));
+                    blocklc.setStackLimit(context.getStackLimit());
+                    // Add the line areas to Area
+                    childLM.addAreas(childPosIter, blocklc);
+                    blocklc.setLeadingSpace(blocklc.getTrailingSpace());
+                    blocklc.setTrailingSpace(new SpaceSpecifier(false));
+                }
+                lineArea.updateExtentsFromChildren();
+                parentLM.addChildArea(lineArea);
             } else {
                 // pos was the Position inside a penalty item, nothing to do
             }
         }
         setCurrentArea(null); // ?? necessary
     }
+
+    public void addChildArea(Area childArea) {
+        // Make sure childArea is inline area
+        if (childArea instanceof InlineArea) {
+            Area parent = getCurrentArea();
+            if (getContext().resolveLeadingSpace()) {
+                addSpace(parent,
+                         getContext().getLeadingSpace().resolve(false),
+                         getContext().getSpaceAdjust());
+            }
+            parent.addChildArea(childArea);
+        }
+    }
+
 }
 
index 1a33d196cf4d29a6cee68afd864ac2c49f29f2e5..77d560df167ebf3c79a06142cecc715826c03eef 100644 (file)
@@ -26,6 +26,7 @@ import java.util.ListIterator;
 import org.apache.fop.fo.FOText;
 import org.apache.fop.fo.flow.Inline;
 import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.KnuthSequence;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthGlue;
@@ -418,6 +419,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     public LinkedList getNextKnuthElements(LayoutContext context,
                                            int alignment) {
         LinkedList returnList = new LinkedList();
+        KnuthSequence sequence = new KnuthSequence(true);
+        returnList.add(sequence);
 
         while (iNextStart < textArray.length) {
             if (textArray[iNextStart] == SPACE
@@ -425,7 +428,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 // normal, breaking space
                 // or non-breaking space
                 if (textArray[iNextStart] == NBSPACE) {
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                           new LeafPosition(this, vecAreaInfo.size() - 1),
                                           false));
@@ -436,23 +439,23 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         (new AreaInfo(iNextStart, (short) (iNextStart + 1),
                                       (short) 1, (short) 0,
                                       wordSpaceIPD, false));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
                                        new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, 0, false,
                                           new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(wordSpaceIPD.opt,
                                        - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
                                        new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthInlineBox(0, 0, 0, 0,
                                       new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                           new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
                                        new LeafPosition(this, -1), true));
                     iNextStart ++;
@@ -464,13 +467,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         (new AreaInfo(iNextStart, (short) (iNextStart + 1),
                                       (short) 1, (short) 0,
                                       wordSpaceIPD, false));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0,
                                        new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, 0, false,
                                           new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(wordSpaceIPD.opt,
                                        - 3 * wordSpaceIPD.opt, 0,
                                        new LeafPosition(this, -1), true));
@@ -482,7 +485,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         (new AreaInfo(iNextStart, (short) (iNextStart + 1),
                                       (short) 1, (short) 0,
                                       wordSpaceIPD, false));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(wordSpaceIPD.opt,
                                        wordSpaceIPD.max - wordSpaceIPD.opt,
                                        wordSpaceIPD.opt - wordSpaceIPD.min,
@@ -495,7 +498,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         (new AreaInfo(iNextStart, (short) (iNextStart + 1),
                                       (short) 1, (short) 0,
                                       wordSpaceIPD, false));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(wordSpaceIPD.opt,
                                        wordSpaceIPD.max - wordSpaceIPD.opt, 0,
                                        new LeafPosition(this, vecAreaInfo.size() - 1), false));
@@ -507,10 +510,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     (new AreaInfo(iNextStart, (short) (iNextStart + 1),
                                   (short) 1, (short) 0,
                                   wordSpaceIPD, false));
-                returnList.add
+                sequence.add
                     (new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                returnList.add
+                sequence.add
                     (new KnuthGlue(wordSpaceIPD.opt,
                                    wordSpaceIPD.max - wordSpaceIPD.opt,
                                    wordSpaceIPD.opt - wordSpaceIPD.min,
@@ -518,12 +521,13 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 iNextStart ++;
             } else if (textArray[iNextStart] == NEWLINE) {
                 // linefeed; this can happen when linefeed-treatment="preserve"
-                // add a penalty item to the list and return
-                returnList.add
+                // add a penalty item to the list and start a new sequence
+                sequence.add
                     (new KnuthPenalty(0, -KnuthElement.INFINITE,
                                       false, null, false));
+                sequence = new KnuthSequence(true);
+                returnList.add(sequence);
                 iNextStart ++;
-                return returnList;
             } else {
                 // the beginning of a word
                 iThisStart = iNextStart;
@@ -548,25 +552,25 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 if (letterSpaceIPD.min == letterSpaceIPD.max) {
                     // constant letter space; simply return a box
                     // whose width includes letter spaces
-                    returnList.add
+                    sequence.add
                         (new KnuthInlineBox(wordIPD.opt, lead, total, middle,
                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
                 } else {
                     // adjustable letter space;
                     // some other KnuthElements are needed
-                    returnList.add
+                    sequence.add
                         (new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
                                       lead, total, middle,
                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                           new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
                                        iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
                                        iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
                                        new LeafPosition(this, -1), true));
-                    returnList.add
+                    sequence.add
                         (new KnuthInlineBox(0, lead, total, middle,
                                             new LeafPosition(this, -1), true));
                 }
@@ -577,10 +581,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     && iTempStart < textArray.length
                     && textArray[iTempStart] != SPACE
                     && textArray[iTempStart] != NBSPACE) {
-                    returnList.add
+                    sequence.add
                         (new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
                                           new LeafPosition(this, -1), false));
-                    returnList.add
+                    sequence.add
                         (new KnuthGlue(letterSpaceIPD.opt,
                                        letterSpaceIPD.max - letterSpaceIPD.opt,
                                        letterSpaceIPD.opt - letterSpaceIPD.min,
@@ -592,6 +596,10 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 iNextStart = iTempStart;
             }
         } // end of while
+        if (((List)returnList.getLast()).size() == 0) {
+            //Remove an empty sequence because of a trailing newline
+            returnList.removeLast();
+        }
         setFinished(true);
         if (returnList.size() > 0) {
             return returnList;
@@ -605,7 +613,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         // look at the Position stored in the first element in oldList
         // which is always a box
         ListIterator oldListIterator = oldList.listIterator();
-        LeafPosition pos = (LeafPosition) ((KnuthBox) oldListIterator.next()).getPosition();
+        KnuthElement el = (KnuthElement)oldListIterator.next();
+        LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
         AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos());
         ai.iLScount ++;
         ai.ipdArea.add(letterSpaceIPD);
index 5a08e608229f37276877cb33e6ca8021e3481607..4153c8547eb1b133a5f50ca29cb1ee262ce147ca 100644 (file)
@@ -52,6 +52,7 @@ import org.apache.fop.area.inline.Container;
 import org.apache.fop.area.inline.ForeignObject;
 import org.apache.fop.area.inline.Image;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.Leader;
 import org.apache.fop.area.inline.Space;
@@ -116,22 +117,22 @@ public abstract class AbstractRenderer
     }
 
     /**
-     *  @see org.apache.fop.render.Renderer
+     *  @see org.apache.fop.render.Renderer#setupFontInfo(FontInfo)
      */
     public abstract void setupFontInfo(FontInfo fontInfo);
 
     /**
-     *  @see org.apache.fop.render.Renderer
+     *  @see org.apache.fop.render.Renderer#setUserAgent(FOUserAgent)
      */
     public void setUserAgent(FOUserAgent agent) {
         userAgent = agent;
     }
 
-    /** @see org.apache.fop.render.Renderer */
+    /** @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */
     public void startRenderer(OutputStream outputStream)
         throws IOException { }
 
-    /** @see org.apache.fop.render.Renderer */
+    /** @see org.apache.fop.render.Renderer#stopRenderer() */
     public void stopRenderer()
         throws IOException { }
 
@@ -148,7 +149,7 @@ public abstract class AbstractRenderer
     }
 
     /**
-     * @see     org.apache.fop.render.Renderer
+     * @see     org.apache.fop.render.Renderer#processOffDocumentItem(OffDocumentItem)
      */
     public void processOffDocumentItem(OffDocumentItem oDI) { }
 
@@ -159,7 +160,7 @@ public abstract class AbstractRenderer
      * page should not be rendered. The page will be rendered at a later time
      * by the call to render page.
      *
-     * @see org.apache.fop.render.Renderer
+     * @see org.apache.fop.render.Renderer#preparePage(PageViewport)
      */
     public void preparePage(PageViewport page) { }
 
@@ -196,14 +197,14 @@ public abstract class AbstractRenderer
         return sb.toString();
     }
 
-    /** @see org.apache.fop.render.Renderer */
+    /** @see org.apache.fop.render.Renderer#startPageSequence(LineArea) */
     public void startPageSequence(LineArea seqTitle) {
         //do nothing
     }
 
     // normally this would be overriden to create a page in the
     // output
-    /** @see org.apache.fop.render.Renderer */
+    /** @see org.apache.fop.render.Renderer#renderPage(PageViewport) */
     public void renderPage(PageViewport page)
         throws IOException, FOPException {
 
@@ -501,6 +502,7 @@ public abstract class AbstractRenderer
                         + parent.getStartIndent() 
                         + line.getStartIndent();
                 renderLineArea(line);
+                //InlineArea child = (InlineArea) line.getInlineAreas().get(0);
                 currentBPPosition += line.getAllocBPD();
             }
             currentIPPosition = saveIP;
@@ -584,6 +586,8 @@ public abstract class AbstractRenderer
             renderText((TextArea) inlineArea);
         } else if (inlineArea instanceof InlineParent) {
             renderInlineParent((InlineParent) inlineArea);
+        } else if (inlineArea instanceof InlineBlockParent) {
+            renderInlineBlockParent((InlineBlockParent) inlineArea);
         } else if (inlineArea instanceof Space) {
             renderInlineSpace((Space) inlineArea);
         } else if (inlineArea instanceof Character) {
@@ -596,12 +600,10 @@ public abstract class AbstractRenderer
     }
 
 
-    /** @see org.apache.fop.render.Renderer */
     protected void renderCharacter(Character ch) {
         currentIPPosition += ch.getAllocIPD();
     }
 
-    /** @see org.apache.fop.render.Renderer */
     protected void renderInlineSpace(Space space) {
         // an inline space moves the inline progression position
         // for the current block by the width or height of the space
@@ -610,17 +612,14 @@ public abstract class AbstractRenderer
         currentIPPosition += space.getAllocIPD();
     }
 
-    /** @see org.apache.fop.render.Renderer */
     protected void renderLeader(Leader area) {
         currentIPPosition += area.getAllocIPD();
     }
 
-    /** @see org.apache.fop.render.Renderer */
     protected void renderText(TextArea text) {
         currentIPPosition += text.getAllocIPD();
     }
 
-    /** @see org.apache.fop.render.Renderer */
     protected void renderInlineParent(InlineParent ip) {
         int saveIP = currentIPPosition;
         Iterator iter = ip.getChildAreas().iterator();
@@ -630,7 +629,13 @@ public abstract class AbstractRenderer
         currentIPPosition = saveIP + ip.getAllocIPD();
     }
 
-    /** @see org.apache.fop.render.Renderer */
+    protected void renderInlineBlockParent(InlineBlockParent ibp) {
+        // For inline content the BP position is updated by the enclosing line area
+        int saveBP = currentBPPosition;
+        renderBlock(ibp.getChildArea());
+        currentBPPosition = saveBP;
+    }
+
     protected void renderViewport(Viewport viewport) {
         Area content = viewport.getContent();
         int saveBP = currentBPPosition;
index 16c6aeb78ba5251fb1db247834b71c639b4e741f..aeb04e11cb3f32a298a8e01b9604024c3665dc7e 100644 (file)
@@ -51,6 +51,7 @@ import org.apache.fop.area.OffDocumentItem;
 import org.apache.fop.area.BookmarkData;
 import org.apache.fop.area.inline.Character;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.area.inline.Viewport;
 import org.apache.fop.area.inline.ForeignObject;
@@ -1302,6 +1303,17 @@ public class PDFRenderer extends PrintRenderer {
         }
     }
 
+    /** @see org.apache.fop.render.AbstractRenderer */
+    protected void renderInlineBlockParent(InlineBlockParent ibp) {
+        float start = currentIPPosition / 1000f;
+        float top = (ibp.getOffset() + currentBPPosition) / 1000f;
+        float width = ibp.getIPD() / 1000f;
+        float height = ibp.getBPD() / 1000f;
+        drawBackAndBorders(ibp, start, top, width, height);
+        
+        super.renderInlineBlockParent(ibp);
+    }
+    
     /**
      * @see org.apache.fop.render.Renderer#renderCharacter(Character)
      */
index 54e2e0673e3a4bbba17adbdd4b496696781e5e6c..30f95a8f4ac03bec2bb81219c0c41288157f78f8 100644 (file)
@@ -60,6 +60,7 @@ import org.apache.fop.area.inline.Container;
 import org.apache.fop.area.inline.ForeignObject;
 import org.apache.fop.area.inline.Image;
 import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.InlineBlockParent;
 import org.apache.fop.area.inline.InlineParent;
 import org.apache.fop.area.inline.Leader;
 import org.apache.fop.area.inline.Space;
@@ -513,13 +514,14 @@ public class XMLRenderer extends AbstractRenderer {
         atts.clear();
         addAreaAttributes(line);
         addTraitAttributes(line);
+        addAttribute("vpos", currentBPPosition);
         startElement("lineArea", atts);
         super.renderLineArea(line);
         endElement("lineArea");
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderViewport(Viewport)
+     * @see org.apache.fop.render.AbstractRenderer#renderViewport(Viewport)
      */
     protected void renderViewport(Viewport viewport) {
         atts.clear();
@@ -544,7 +546,7 @@ public class XMLRenderer extends AbstractRenderer {
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderContainer(Container)
+     * @see org.apache.fop.render.AbstractRenderer#renderContainer(Container)
      */
     public void renderContainer(Container cont) {
         startElement("container");
@@ -570,7 +572,7 @@ public class XMLRenderer extends AbstractRenderer {
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderCharacter(Character)
+     * @see org.apache.fop.render.AbstractRenderer#renderCharacter(Character)
      */
     protected void renderCharacter(org.apache.fop.area.inline.Character ch) {
         atts.clear();
@@ -582,7 +584,7 @@ public class XMLRenderer extends AbstractRenderer {
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderInlineSpace(Space)
+     * @see org.apache.fop.render.AbstractRenderer#renderInlineSpace(Space)
      */
     protected void renderInlineSpace(Space space) {
         atts.clear();
@@ -592,7 +594,7 @@ public class XMLRenderer extends AbstractRenderer {
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderText(TextArea)
+     * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea)
      */
     protected void renderText(TextArea text) {
         atts.clear();
@@ -603,6 +605,7 @@ public class XMLRenderer extends AbstractRenderer {
             addAttribute("tlsadjust", text.getTextLetterSpaceAdjust());
         }
         addAttribute("vpos", text.getOffset());
+        addAreaAttributes(text);
         addTraitAttributes(text);
         startElement("text", atts);
         characters(text.getTextArea());
@@ -611,18 +614,28 @@ public class XMLRenderer extends AbstractRenderer {
     }
 
     /**
-     * @see org.apache.fop.render.Renderer#renderInlineParent(InlineParent)
+     * @see org.apache.fop.render.AbstractRenderer#renderInlineParent(InlineParent)
      */
     protected void renderInlineParent(InlineParent ip) {
         atts.clear();
+        addAreaAttributes(ip);
         addTraitAttributes(ip);
         startElement("inlineparent", atts);
         super.renderInlineParent(ip);
         endElement("inlineparent");
     }
 
+    protected void renderInlineBlockParent(InlineBlockParent ibp) {
+        atts.clear();
+        addAreaAttributes(ibp);
+        addTraitAttributes(ibp);
+        startElement("inlineblockparent", atts);
+        super.renderInlineBlockParent(ibp);
+        endElement("inlineblockparent");
+    }
+
     /**
-     * @see org.apache.fop.render.Renderer#renderLeader(Leader)
+     * @see org.apache.fop.render.AbstractRenderer#renderLeader(Leader)
      */
     protected void renderLeader(Leader area) {
         String style = "solid";
@@ -656,7 +669,7 @@ public class XMLRenderer extends AbstractRenderer {
         super.renderLeader(area);
     }
 
-    /** @see org.apache.fop.render.AbstractRenderer */
+    /** @see org.apache.fop.render.AbstractRenderer#getMimeType() */
     public String getMimeType() {
         return XML_MIME_TYPE;
     }
index 6bc9933a01ab08d32ba64299f6e340427c5ac673..255cff900979e88308518273e4e7cdbcb34b0e45 100644 (file)
@@ -44,6 +44,10 @@ public class LoggingElementListObserver implements Observer {
         }
         log.debug(" ");
         log.debug("ElementList: category=" + category + ", id=" + id);
+        if (elementList == null) {
+            log.debug("<<empty list>>");
+            return;
+        }
         ListIterator tempIter = elementList.listIterator();
         KnuthElement temp;
         while (tempIter.hasNext()) {
index 585dec6dc0dc238597c2a4d85d1296314370f608..a9c9bc52be644e49bb56490723e34041010cb786 100644 (file)
@@ -1,6 +1,6 @@
 external-graphic1.xml
 external-graphic2.xml
-inline1.xml
+inline-block2.xml
 keep-with-previous2.xml
 keep-with-previous3.xml
 keep-with-previous4.xml
@@ -14,4 +14,4 @@ table-border-collapse1.xml
 table-border-collapse2.xml
 table-border-separate1.xml
 table-column4.xml
-table-fixed2.xml
+table-fixed2.xml
\ No newline at end of file
diff --git a/test/layoutengine/testcases/inline-block1.xml b/test/layoutengine/testcases/inline-block1.xml
new file mode 100644 (file)
index 0000000..ef6ae86
--- /dev/null
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2005 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks block content in fo:inline. It stresses the nesting by letting the fo:inline have a background color.
+    </p>
+  </info>
+  <fo>
+    <fo:root
+      xmlns:fo="http://www.w3.org/1999/XSL/Format"
+      xmlns:svg="http://www.w3.org/2000/svg">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="simpleA4"
+          page-height="29.7cm" page-width="21cm"
+          margin-top="2cm" margin-bottom="2cm"
+          margin-left="2cm" margin-right="2cm">
+          <fo:region-body
+            margin-top="1.2in" margin-bottom="1in"
+            margin-left="1in" margin-right="1in"/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+
+      <fo:page-sequence master-reference="simpleA4">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block language="en" country="US"
+            hyphenate="true" text-align="justify">
+            The appropriate values of the parameters can be obtained from <fo:inline background-color="lightgray">the following equations:
+            <fo:block>
+              w1 + w2 + w3 = W,
+            </fo:block>
+            <fo:block>
+              y1 + y2 + y3 = Y,
+            </fo:block>where W and Y follow from the previous rule</fo:inline>. This completes our argument.
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker">
+      <box w="14400"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <box w="14400"/>
+      <skip>3</skip>
+    </element-list>
+    
+    <!-- the following check sequence verifies background traits caused by the inline element. -->
+    <true xpath="not(boolean(//flow/block/@background))"/>
+    <true xpath="not(boolean(//flow/block/lineArea[1]/child::*[1]/@background))"/>
+    
+    <true xpath="boolean(//flow/block/lineArea[2]/inlineparent[1])"/>
+    <eval expected="color=#d3d3d3,repeat=0,horiz=0,vertical=0" xpath="//flow/block/lineArea[2]/child::*[1]/@background"/>
+
+    <true xpath="boolean(//flow/block/lineArea[3]/inlineblockparent[1])"/>
+    <eval expected="color=#d3d3d3,repeat=0,horiz=0,vertical=0" xpath="//flow/block/lineArea[3]/child::*[1]/@background"/>
+    <true xpath="not(boolean(//flow/block/lineArea[3]/inlineblockparent[1]/block/@background))"/>
+
+    <true xpath="boolean(//flow/block/lineArea[4]/inlineblockparent[1])"/>
+    <eval expected="color=#d3d3d3,repeat=0,horiz=0,vertical=0" xpath="//flow/block/lineArea[4]/child::*[1]/@background"/>
+    <true xpath="not(boolean(//flow/block/lineArea[4]/inlineblockparent[1]/block/@background))"/>
+
+    <eval expected="inlineparent" xpath="local-name(//flow/block/lineArea[5]/child::*[1])"/>
+    <eval expected="text" xpath="local-name(//flow/block/lineArea[5]/child::*[2])"/>
+    <eval expected="color=#d3d3d3,repeat=0,horiz=0,vertical=0" xpath="//flow/block/lineArea[5]/child::*[1]/@background"/>
+
+    <true xpath="not(boolean(//flow/block/lineArea[6]/child::*[1]/@background))"/>
+
+    <!-- the following check sequence verifies size traits so the background is actually painted correctly. -->
+    <eval expected="86400" xpath="//flow/block/@bpd"/>
+    <eval expected="337891" xpath="//flow/block/@ipd"/>
+    <eval expected="14400" xpath="//flow/block/lineArea[3]/inlineblockparent[1]/@bpd"/>
+    <eval expected="337891" xpath="//flow/block/lineArea[3]/inlineblockparent[1]/@ipd"/>
+    <eval expected="14400" xpath="//flow/block/lineArea[4]/inlineblockparent[1]/@bpd"/>
+    <eval expected="337891" xpath="//flow/block/lineArea[4]/inlineblockparent[1]/@ipd"/>
+
+  </checks>
+</testcase>
diff --git a/test/layoutengine/testcases/inline-block2.xml b/test/layoutengine/testcases/inline-block2.xml
new file mode 100644 (file)
index 0000000..60bdea9
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Copyright 2005 The Apache Software Foundation
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks block content in fo:inline. It stresses the nesting by letting the fo:inline have a background color.
+    </p>
+  </info>
+  <fo>
+    <fo:root
+      xmlns:fo="http://www.w3.org/1999/XSL/Format"
+      xmlns:svg="http://www.w3.org/2000/svg">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="simpleA4"
+          page-height="29.7cm" page-width="21cm"
+          margin-top="2cm" margin-bottom="2cm"
+          margin-left="2cm" margin-right="2cm">
+          <fo:region-body
+            margin-top="1.2in" margin-bottom="1in"
+            margin-left="1in" margin-right="1in"/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+
+      <fo:page-sequence master-reference="simpleA4">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block language="en" country="US"
+            hyphenate="true" text-align="justify">
+            The appropriate values of the parameters can be obtained from <fo:inline background-color="lightgray">the following table:
+            <fo:block>
+          <fo:table table-layout="fixed" border-collapse="separate" margin="0pt" border="solid 5pt" padding="5pt" width="4in + 10pt + 10pt" background-color="gray">
+            <fo:table-column column-width="2in"/>
+            <fo:table-column column-width="2in"/>
+            <fo:table-body start-indent="0pt" end-indent="0pt">
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>w1 + w2 + w3</fo:block>
+                </fo:table-cell>
+                <fo:table-cell background-color="yellow">
+                  <fo:block>W</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell background-color="orange">
+                  <fo:block>y1 + y2 + y3</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Y</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+            </fo:block>where W and Y follow from the previous rule</fo:inline>. This completes our argument.
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker">
+      <box w="14400"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="10000" aux="true"/>
+      <box w="14400"/>
+      <penalty w="20000" p="0"/>
+      <box w="14400"/>
+      <box w="10000" aux="true"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <box w="14400"/>
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>
index 5f7e74b35328630da2d49753daa0bfc03c30e4dc..f64ebe37eb8d86271ad6f40ca4563bda16cf5ee6 100644 (file)
     </fo:root>
   </fo>
   <checks>
-    <!-- currently causes a ClassCastException -->
+    <element-list category="breaker">
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="0" aux="true"/> <!-- this is from the empty block -->
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <skip>3</skip>
+    </element-list>
   </checks>
 </testcase>