]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Moved inline-level LMs and support classes to "inline" subpackage.
authorJeremias Maerki <jeremias@apache.org>
Mon, 18 Jul 2005 15:03:47 +0000 (15:03 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 18 Jul 2005 15:03:47 +0000 (15:03 +0000)
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@219509 13f79535-47bb-0310-9956-ffa450edef68

57 files changed:
src/java/org/apache/fop/fo/flow/BasicLink.java
src/java/org/apache/fop/fo/flow/BidiOverride.java
src/java/org/apache/fop/fo/flow/InlineContainer.java
src/java/org/apache/fop/fo/flow/InlineLevel.java
src/java/org/apache/fop/fo/flow/InstreamForeignObject.java
src/java/org/apache/fop/fo/flow/Leader.java
src/java/org/apache/fop/layoutmgr/BasicLinkLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/BidiLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
src/java/org/apache/fop/layoutmgr/CharacterLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/ContentLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/ExternalGraphicLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
src/java/org/apache/fop/layoutmgr/FootnoteLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/HyphContext.java [deleted file]
src/java/org/apache/fop/layoutmgr/ICLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/InlineLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/InlineLevelLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java [deleted file]
src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java [deleted file]
src/java/org/apache/fop/layoutmgr/KnuthParagraph.java [deleted file]
src/java/org/apache/fop/layoutmgr/LayoutContext.java
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
src/java/org/apache/fop/layoutmgr/LeaderLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/LineLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/LineLayoutPossibilities.java [deleted file]
src/java/org/apache/fop/layoutmgr/PageNumberCitationLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/PageNumberLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
src/java/org/apache/fop/layoutmgr/TextLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/WrapperLayoutManager.java [deleted file]
src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/BidiLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/HyphContext.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/ICLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java [new file with mode: 0755]
src/java/org/apache/fop/layoutmgr/inline/InlineLevelLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/LeafNodeLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/LineLayoutPossibilities.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java [new file with mode: 0644]

index 6832335fc4467b401a66b5cf30cf4c604d468568..e205fbe48fb2aa76b258b69e54ade600ab50fa1c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-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.
 
 package org.apache.fop.fo.flow;
 
-// Java
-import java.util.List;
-
 import org.xml.sax.Locator;
 
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.ValidationException;
-import org.apache.fop.layoutmgr.BasicLinkLayoutManager;
 
 /**
  * The fo:basic-link formatting object.
@@ -118,14 +114,14 @@ public class BasicLink extends Inline {
     }
 
     /**
-     * Return the "internal-destination" property.
+     * @return the "internal-destination" property.
      */
     public String getInternalDestination() {
         return internalDestination;
     }
 
     /**
-     * Return the "external-destination" property.
+     * @return the "external-destination" property.
      */
     public String getExternalDestination() {
         return externalDestination;
index d184e83a53afc89408a1aaf0fd9efda4667a6222..f8c28d4e0fe15034f840ab5d13b0efa86f36e4b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-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.
 
 package org.apache.fop.fo.flow;
 
-// Java
-import java.util.ArrayList;
-import java.util.List;
-
 import org.xml.sax.Locator;
 
 import org.apache.fop.apps.FOPException;
@@ -35,9 +31,6 @@ import org.apache.fop.fo.properties.CommonAural;
 import org.apache.fop.fo.properties.CommonFont;
 import org.apache.fop.fo.properties.CommonRelativePosition;
 import org.apache.fop.fo.properties.SpaceProperty;
-import org.apache.fop.layoutmgr.BidiLayoutManager;
-import org.apache.fop.layoutmgr.InlineLayoutManager;
-import org.apache.fop.layoutmgr.LayoutManager;
 
 /**
  * fo:bidi-override element.
index 7f53f00c0d7eab7889e57cba80fa7b0a1dcd112b..380ff8b7dd8d7b357bc2b51c5ae6cc35f7026c36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-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.
 
 package org.apache.fop.fo.flow;
 
-// Java
-import java.util.ArrayList;
-import java.util.List;
-
 import org.xml.sax.Locator;
 
 import org.apache.fop.apps.FOPException;
@@ -36,13 +32,12 @@ import org.apache.fop.fo.properties.CommonMarginInline;
 import org.apache.fop.fo.properties.CommonRelativePosition;
 import org.apache.fop.fo.properties.KeepProperty;
 import org.apache.fop.fo.properties.LengthRangeProperty;
-import org.apache.fop.layoutmgr.ICLayoutManager;
-import org.apache.fop.layoutmgr.LayoutManager;
 
 /**
  * Class modelling the fo:inline-container object.
  */
 public class InlineContainer extends FObj {
+    
     // The value of properties relevant for fo:inline-container.
     private CommonBorderPaddingBackground commonBorderPaddingBackground;
     private CommonMarginInline commonMarginInline;
@@ -138,7 +133,7 @@ public class InlineContainer extends FObj {
     }
 
     /**
-     * Return the "id" property.
+     * @return the "id" property.
      */
     public String getId() {
         return id;
index 6cdb92b4041a97fcb564fb4ed3259b80b18e10ea..096eac768083cf59bf68110e8139fa2876f16085 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004 The Apache Software Foundation.
+ * Copyright 2004-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.
@@ -18,8 +18,6 @@
 
 package org.apache.fop.fo.flow;
 
-import java.util.List;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.datatypes.ColorType;
 import org.apache.fop.datatypes.Length;
@@ -31,13 +29,14 @@ import org.apache.fop.fo.properties.CommonAural;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonFont;
 import org.apache.fop.fo.properties.CommonMarginInline;
-import org.apache.fop.layoutmgr.InlineLayoutManager;
 
 /**
  * Class modelling the commonalities of several inline-level
  * formatting objects.
  */
 public abstract class InlineLevel extends FObjMixed {
+    
+    // The value of properties relevant for inline-level FOs.
     protected CommonBorderPaddingBackground commonBorderPaddingBackground;
     protected CommonAccessibility commonAccessibility;
     protected CommonMarginInline commonMarginInline;
@@ -70,28 +69,28 @@ public abstract class InlineLevel extends FObjMixed {
     }
 
     /**
-     * Return the Common Margin Properties-Inline.
+     * @return the Common Margin Properties-Inline.
      */
     public CommonMarginInline getCommonMarginInline() {
         return commonMarginInline;
     }
 
     /**
-     * Return the Common Border, Padding, and Background Properties.
+     * @return the Common Border, Padding, and Background Properties.
      */
     public CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
         return commonBorderPaddingBackground;
     } 
 
     /**
-     * Return the Common Font Properties.
+     * @return the Common Font Properties.
      */
     public CommonFont getCommonFont() {
         return commonFont;
     }
 
     /**
-     * Return the "color" property.
+     * @return the "color" property.
      */
     public ColorType getColor() {
         return color;
index fc6baea5093204d3638d9deed83414f51d98bda8..563de2f145a8185b07508cc906fd0c902b62151d 100644 (file)
@@ -188,84 +188,84 @@ public class InstreamForeignObject extends FObj {
     }
 
     /**
-     * Return the "id" property.
+     * @return the "id" property.
      */
     public String getId() {
         return id;
     }
 
     /**
-     * Return the Common Border, Padding, and Background Properties.
+     * @return the Common Border, Padding, and Background Properties.
      */
     public CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
         return commonBorderPaddingBackground;
     }
 
     /**
-     * Return the "line-height" property.
+     * @return the "line-height" property.
      */
     public Length getLineHeight() {
         return lineHeight;
     }
 
     /**
-     * Return the "inline-progression-dimension" property.
+     * @return the "inline-progression-dimension" property.
      */
     public LengthRangeProperty getInlineProgressionDimension() {
         return inlineProgressionDimension;
     }
 
     /**
-     * Return the "block-progression-dimension" property.
+     * @return the "block-progression-dimension" property.
      */
     public LengthRangeProperty getBlockProgressionDimension() {
         return blockProgressionDimension;
     }
 
     /**
-     * Return the "height" property.
+     * @return the "height" property.
      */
     public Length getHeight() {
         return height;
     }
 
     /**
-     * Return the "width" property.
+     * @return the "width" property.
      */
     public Length getWidth() {
         return width;
     }
 
     /**
-     * Return the "content-height" property.
+     * @return the "content-height" property.
      */
     public Length getContentHeight() {
         return contentHeight;
     }
 
     /**
-     * Return the "content-width" property.
+     * @return the "content-width" property.
      */
     public Length getContentWidth() {
         return contentWidth;
     }
 
     /**
-     * Return the "scaling" property.
+     * @return the "scaling" property.
      */
     public int getScaling() {
         return scaling;
     }
 
     /**
-     * Return the "vertical-align" property.
+     * @return the "vertical-align" property.
      */
     public int getVerticalAlign() {
         return verticalAlign;
     }
 
     /**
-     * Return the "overflow" property.
+     * @return the "overflow" property.
      */
     public int getOverflow() {
         return overflow;
@@ -285,9 +285,7 @@ public class InstreamForeignObject extends FObj {
         return FO_INSTREAM_FOREIGN_OBJECT;
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getLayoutDimension(org.apache.fop.datatypes.PercentBase.DimensionType)
-     */
+    /** @see org.apache.fop.fo.FObj */
     public Number getLayoutDimension(PercentBase.LayoutDimension key) {
         if (key == PercentBase.IMAGE_INTRINSIC_WIDTH) {
             return new Integer(getIntrinsicWidth());
@@ -337,4 +335,8 @@ public class InstreamForeignObject extends FObj {
         }
     }
     
+    /** @see org.apache.fop.fo.FONode#addChildNode(org.apache.fop.fo.FONode) */
+    protected void addChildNode(FONode child) throws FOPException {
+        super.addChildNode(child);
+    }
 }
index 16387d6a3e9c13d8e385495f43f5f23d2e64cc1a..f8e67130fcf9e1819a0e3eb70c5884a91260b4f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-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.
@@ -18,9 +18,6 @@
 
 package org.apache.fop.fo.flow;
 
-// Java
-import java.util.List;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.fo.FONode;
@@ -29,7 +26,6 @@ import org.apache.fop.fo.properties.CommonRelativePosition;
 import org.apache.fop.fo.properties.KeepProperty;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.fo.properties.SpaceProperty;
-import org.apache.fop.layoutmgr.LeaderLayoutManager;
 
 /**
  * Class modelling fo:leader object.
@@ -105,6 +101,8 @@ public class Leader extends InlineLevel {
             // use inline layout manager to create inline areas
             // add the inline parent multiple times until leader full
             break;
+        default:
+            throw new RuntimeException("Invalid leader pattern: " + leaderPattern);
         }
         // letterSpacing = pList.get(PR_LETTER_SPACING);
         // textShadow = pList.get(PR_TEXT_SHADOW);
@@ -120,56 +118,56 @@ public class Leader extends InlineLevel {
 
 
     /**
-     * Return the "id" property.
+     * @return the "id" property.
      */
     public String getId() {
         return id;
     }
 
     /**
-     * Return the "rule-style" property.
+     * @return the "rule-style" property.
      */
     public int getRuleStyle() {
         return ruleStyle;
     }
 
     /**
-     * Return the "rule-thickness" property.
+     * @return the "rule-thickness" property.
      */
     public Length getRuleThickness() {
         return ruleThickness;
     }
 
     /**
-     * Return the "leader-alignment" property.
+     * @return the "leader-alignment" property.
      */
     public int getLeaderAlignment() {
         return leaderAlignment;
     }
 
     /**
-     * Return the "leader-length" property.
+     * @return the "leader-length" property.
      */
     public LengthRangeProperty getLeaderLength() {
         return leaderLength;
     }
 
     /**
-     * Return the "leader-pattern" property.
+     * @return the "leader-pattern" property.
      */
     public int getLeaderPattern() {
         return leaderPattern;
     }
 
     /**
-     * Return the "leader-pattern-width" property.
+     * @return the "leader-pattern-width" property.
      */
     public Length getLeaderPatternWidth() {
         return leaderPatternWidth;
     }
 
     /**
-     * Return the "vertical-align" property.
+     * @return the "vertical-align" property.
      */
     public int getVerticalAlign() {
         return verticalAlign; 
diff --git a/src/java/org/apache/fop/layoutmgr/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BasicLinkLayoutManager.java
deleted file mode 100644 (file)
index 38a4b29..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-import org.apache.fop.fo.flow.BasicLink;
-import org.apache.fop.area.inline.InlineParent;
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.LinkResolver;
-import org.apache.fop.area.PageViewport;
-
-/**
- * LayoutManager for the fo:basic-link formatting object
- */
-public class BasicLinkLayoutManager extends InlineLayoutManager {
-    private BasicLink fobj;
-    
-    /**
-     * Create an fo:basic-link layout manager.
-     *
-     * @param node the formatting object that creates the area
-     */
-    public BasicLinkLayoutManager(BasicLink node) {
-        super(node);
-        fobj = node;
-    }
-
-    protected InlineParent createArea() {
-        InlineParent area = super.createArea();
-        setupBasicLinkArea(parentLM, area);
-        return area;
-    }
-    
-    private void setupBasicLinkArea(LayoutManager parentLM,
-                                      InlineParent area) {
-         if (fobj.getExternalDestination() != null) {
-             area.addTrait(Trait.EXTERNAL_LINK, fobj.getExternalDestination());
-         } else {
-             String idref = fobj.getInternalDestination();
-             PageViewport page = getPSLM().getFirstPVWithID(idref);
-             if (page != null) {
-                 area.addTrait(Trait.INTERNAL_LINK, page.getKey());
-             } else {
-                 LinkResolver res = new LinkResolver(idref, area);
-                 getPSLM().addUnresolvedArea(idref, res);
-             }
-         }
-     }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/BidiLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BidiLayoutManager.java
deleted file mode 100644 (file)
index bffc4c7..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.fo.flow.BidiOverride;
-
-
-/**
- * If this bidi has a different writing mode direction
- * ltr or rtl than its parent writing mode then this
- * reverses the inline areas (at the character level).
- */
-public class BidiLayoutManager extends LeafNodeLayoutManager {
-
-    private List children;
-
-    public BidiLayoutManager(BidiOverride node, InlineLayoutManager cLM) {
-        super(node);
-        children = new ArrayList();
-/*
-        for (int count = cLM.size() - 1; count >= 0; count--) {
-            InlineArea ia = cLM.get(count);
-            if (ia instanceof Word) {
-                // reverse word
-                Word word = (Word) ia;
-                StringBuffer sb = new StringBuffer(word.getWord());
-                word.setWord(sb.reverse().toString());
-            }
-            children.add(ia);
-        }
-*/
-    }
-
-    public int size() {
-        return children.size();
-    }
-
-    public InlineArea get(int index) {
-        return (InlineArea) children.get(index);
-    }
-
-}
index 9f48f20b60c489121a1a78af72b82833718b5e23..46dbf14072ae9b209bfe7161e9f4753af368f0f9 100644 (file)
@@ -23,6 +23,8 @@ import java.util.ListIterator;
 import java.util.List;
 
 import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
+import org.apache.fop.layoutmgr.inline.LineLayoutManager;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Block;
 import org.apache.fop.area.LineArea;
index fa65dfda93357e6cc122f2126eab28dd5e2211a8..c86281c4226253e3f1b07ae668ec4777222f1579 100644 (file)
@@ -30,6 +30,7 @@ import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.SpaceProperty;
+import org.apache.fop.layoutmgr.inline.LineLayoutManager;
 import org.apache.fop.traits.MinOptMax;
 
 /**
index 98ba692b337ea1c404534f0a39024cae581c23f0..f71a9fd7de37e9544a18f09cb44ba54893235ba6 100644 (file)
@@ -135,7 +135,7 @@ public abstract class BreakingAlgorithm {
 
 
     // this class represent a feasible breaking point
-    protected class KnuthNode {
+    public class KnuthNode {
         /** index of the breakpoint represented by this node */
         public int position;
 
diff --git a/src/java/org/apache/fop/layoutmgr/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/CharacterLayoutManager.java
deleted file mode 100644 (file)
index 3352dc5..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.fo.flow.Character;
-import org.apache.fop.fonts.Font;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.Trait;
-import org.apache.fop.traits.MinOptMax;
-import org.apache.fop.traits.SpaceVal;
-
-import java.util.List;
-import java.util.LinkedList;
-
-/**
- * LayoutManager for the fo:character formatting object
- */
-public class CharacterLayoutManager extends LeafNodeLayoutManager {
-    private Character fobj;
-    private MinOptMax letterSpaceIPD;
-    private int hyphIPD;
-    private Font fs;
-
-    /**
-     * Constructor
-     *
-     * @param node the fo:character formatting object
-     * @todo better null checking of node
-     */
-    public CharacterLayoutManager(Character node) {
-        super(node);
-        fobj = node;
-        InlineArea inline = getCharacterInlineArea(node);
-        setCurrentArea(inline);
-        setAlignment(fobj.getVerticalAlign());
-        fs = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
-
-        SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing());
-        letterSpaceIPD = ls.getSpace();
-        hyphIPD = fs.getCharWidth(fobj.getCommonHyphenation().hyphenationCharacter);
-    }
-
-    private InlineArea getCharacterInlineArea(Character node) {
-        org.apache.fop.area.inline.Character ch =
-            new org.apache.fop.area.inline.Character(node.getCharacter());
-        TraitSetter.addTextDecoration(ch, fobj.getTextDecoration());
-        return ch;
-    }
-
-    /**
-     * Offset this area.
-     * Offset the inline area in the bpd direction when adding the
-     * inline area.
-     * This is used for vertical alignment.
-     * Subclasses should override this if necessary.
-     * @param area the inline area to be updated
-     * @param context the layout context used for adding the area
-     */
-    protected void offsetArea(InlineArea area, LayoutContext context) {
-        int bpd = area.getBPD();
-        switch (verticalAlignment) {
-            case EN_MIDDLE:
-                area.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2);
-            break;
-            case EN_TOP:
-                area.setOffset(fs.getAscender());
-            break;
-            case EN_BOTTOM:
-                area.setOffset(context.getLineHeight() - bpd + fs.getAscender());
-            break;
-            case EN_BASELINE:
-            default:
-                area.setOffset(context.getBaseline());
-            break;
-        }
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        MinOptMax ipd;
-        curArea = get(context);
-        LinkedList returnList = new LinkedList();
-
-        if (curArea == null) {
-            setFinished(true);
-            return null;
-        }
-
-        ipd = new MinOptMax(fs.getCharWidth(((org.apache.fop.area.inline.Character) curArea).getChar().charAt(0)));
-
-        curArea.setIPD(ipd.opt);
-        curArea.setBPD(fs.getAscender() - fs.getDescender());
-
-        // offset is set in the offsetArea() method
-        //curArea.setOffset(textInfo.fs.getAscender());
-        //curArea.setOffset(context.getBaseline()); 
-
-        curArea.addTrait(Trait.FONT_NAME, fs.getFontName());
-        curArea.addTrait(Trait.FONT_SIZE, new Integer(fs.getFontSize()));
-        curArea.addTrait(Trait.COLOR, fobj.getColor());
-
-        int bpd = curArea.getBPD();
-        int lead = 0;
-        int total = 0;
-        int middle = 0;
-        switch (verticalAlignment) {
-            case EN_MIDDLE  : middle = bpd / 2 ;
-                                         break;
-            case EN_TOP     : // fall through
-            case EN_BOTTOM  : total = bpd;
-                                         break;
-            case EN_BASELINE: // fall through
-            default                    : lead = fs.getAscender();
-                                         total = bpd;
-                                         break;
-        }
-
-        // create the AreaInfo object to store the computed values
-        areaInfo = new AreaInfo((short) 0, ipd, false,
-                                lead, total, middle);
-
-        // node is a fo:Character
-        if (letterSpaceIPD.min == letterSpaceIPD.max) {
-            // constant letter space, only return a box
-            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
-                                        areaInfo.total, areaInfo.middle,
-                                        new LeafPosition(this, 0), false));
-        } else {
-            // adjustable letter space, return a sequence of elements;
-            // at the moment the character is supposed to have no letter spaces,
-            // but returning this sequence allows us to change only one element
-            // if addALetterSpaceTo() is called
-            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
-                                        areaInfo.total, areaInfo.middle,
-                                        new LeafPosition(this, 0), false));
-            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                            new LeafPosition(this, -1), true));
-            returnList.add(new KnuthGlue(0, 0, 0,
-                                         new LeafPosition(this, -1), true));
-            returnList.add(new KnuthInlineBox(0, 0, 0, 0,
-                                        new LeafPosition(this, -1), true));
-        }
-
-        setFinished(true);
-        return returnList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position bp) {
-        sbChars.append
-            (((org.apache.fop.area.inline.Character) curArea).getChar());
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        if (hc.getNextHyphPoint() == 1) {
-            // the character ends a syllable
-            areaInfo.bHyphenated = true;
-            bSomethingChanged = true;
-        } else {
-            // hc.getNextHyphPoint() returned -1 (no more hyphenation points)
-            // or a number > 1;
-            // the character does not end a syllable
-        }
-        hc.updateOffset(1);
-    }
-
-    public boolean applyChanges(List oldList) {
-        setFinished(false);
-        if (bSomethingChanged) {
-            // there is nothing to do,
-            // possible changes have already been applied
-            // in the hyphenate() method
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              int flaggedPenalty,
-                                              int alignment) {
-        if (isFinished()) {
-            return null;
-        }
-
-        LinkedList returnList = new LinkedList();
-
-        if (letterSpaceIPD.min == letterSpaceIPD.max
-            || areaInfo.iLScount == 0) {
-            // constant letter space, or no letter space
-            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
-                                        areaInfo.total, areaInfo.middle,
-                                        new LeafPosition(this, 0), false));
-            if (areaInfo.bHyphenated) {
-                returnList.add
-                    (new KnuthPenalty(hyphIPD, flaggedPenalty, true,
-                                      new LeafPosition(this, -1), false));
-            }
-        } else {
-            // adjustable letter space
-            returnList.add
-                (new KnuthInlineBox(areaInfo.ipdArea.opt
-                              - areaInfo.iLScount * letterSpaceIPD.opt,
-                              areaInfo.lead, areaInfo.total, areaInfo.middle,
-                              new LeafPosition(this, 0), false));
-            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                            new LeafPosition(this, -1), true));
-            returnList.add
-                (new KnuthGlue(areaInfo.iLScount * letterSpaceIPD.opt,
-                               areaInfo.iLScount * letterSpaceIPD.max - letterSpaceIPD.opt,
-                               areaInfo.iLScount * letterSpaceIPD.opt - letterSpaceIPD.min,
-                               new LeafPosition(this, -1), true));
-            returnList.add(new KnuthInlineBox(0, 0, 0, 0,
-                                        new LeafPosition(this, -1), true));
-            if (areaInfo.bHyphenated) {
-                returnList.add
-                    (new KnuthPenalty(hyphIPD, flaggedPenalty, true,
-                                      new LeafPosition(this, -1), false));
-            }
-        }
-
-        setFinished(true);
-        return returnList;
-    }
-
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/ContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ContentLayoutManager.java
deleted file mode 100644 (file)
index 945cdf5..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.apps.FOUserAgent;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.pagination.Title;
-import org.apache.fop.area.Area;
-import org.apache.fop.area.LineArea;
-import org.apache.fop.area.inline.InlineArea;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.ArrayList;
-import org.apache.fop.traits.MinOptMax;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Content Layout Manager.
- * For use with objects that contain inline areas such as
- * leader use-content and title.
- */
-public class ContentLayoutManager implements InlineLevelLayoutManager {
-    private FOUserAgent userAgent;
-    private Area holder;
-    private int stackSize;
-    private LayoutManager parentLM;
-    private InlineLevelLayoutManager childLM = null;
-
-    /**
-     * logging instance
-     */
-    protected static Log log = LogFactory.getLog(LayoutManager.class);
-
-    /**
-     * Constructs a new ContentLayoutManager
-     *
-     * @param area  The parent area
-     */
-    public ContentLayoutManager(Area area, LayoutManager parentLM) {
-        holder = area;
-        this.parentLM = parentLM;
-    }
-
-    /**
-     * Constructor using a fo:title formatting object and its
-     * PageSequenceLayoutManager parent.
-     */
-    public ContentLayoutManager(Title foTitle, PageSequenceLayoutManager pslm) {
-        // get breaks then add areas to title
-        this.parentLM = pslm;
-        holder = new LineArea();
-
-        setUserAgent(foTitle.getUserAgent());
-
-        // use special layout manager to add the inline areas
-        // to the Title.
-        InlineLayoutManager lm;
-        lm = new InlineLayoutManager(foTitle);
-        addChildLM(lm);
-        fillArea(lm);
-    }
-
-    public void fillArea(LayoutManager curLM) {
-
-        int ipd = 1000000;
-
-        LayoutContext childLC = new LayoutContext(LayoutContext.NEW_AREA);
-        childLC.setLeadingSpace(new SpaceSpecifier(false));
-        childLC.setTrailingSpace(new SpaceSpecifier(false));
-        // set stackLimit for lines
-        childLC.setStackLimit(new MinOptMax(ipd));
-        childLC.setRefIPD(ipd);
-
-        int lineHeight = 14000;
-        int lead = 12000;
-        int follow = 2000;
-
-        int halfLeading = (lineHeight - lead - follow) / 2;
-        // height before baseline
-        int lineLead = lead + halfLeading;
-        // maximum size of top and bottom alignment
-        int maxtb = follow + halfLeading;
-        // max size of middle alignment below baseline
-        int middlefollow = maxtb;
-
-        stackSize = 0;
-
-        LinkedList contentList =
-            getNextKnuthElements(childLC, Constants.EN_START);
-        ListIterator contentIter = contentList.listIterator();
-        while (contentIter.hasNext()) {
-            KnuthElement element = (KnuthElement) contentIter.next();
-            if (element.isBox()) {
-                KnuthInlineBox box = (KnuthInlineBox) element;
-                if (box.getLead() > lineLead) {
-                    lineLead = box.getLead();
-                }
-                if (box.getTotal() > maxtb) {
-                    maxtb = box.getTotal();
-                }
-                // Is this needed? cf. LineLM.makeLineBreakPosition
-                // if (box.getMiddle() > lineLead) {
-                //     lineLead = box.getMiddle();
-                // }
-                if (box.getMiddle() > middlefollow) {
-                    middlefollow = box.getMiddle();
-                }
-            }
-        }
-
-        if (maxtb - lineLead > middlefollow) {
-            middlefollow = maxtb - lineLead;
-        }
-
-        LayoutContext lc = new LayoutContext(0);
-        lc.setBaseline(lineLead);
-        lc.setLineHeight(lineHeight);
-
-        lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
-        lc.setLeadingSpace(new SpaceSpecifier(false));
-        lc.setTrailingSpace(new SpaceSpecifier(false));
-        KnuthPossPosIter contentPosIter =
-            new KnuthPossPosIter(contentList, 0, contentList.size());
-        curLM.addAreas(contentPosIter, lc);
-    }
-
-    public void addAreas(PositionIterator posIter, LayoutContext context) {
-        // add the content areas
-        // the area width has already been adjusted, and it must remain unchanged
-        // so save its value before calling addAreas, and set it again afterwards
-        int savedIPD = ((InlineArea)holder).getIPD();
-        // set to zero the ipd adjustment ratio, to avoid spaces in the pattern
-        // to be modified
-        LayoutContext childContext = new LayoutContext(context);
-        childContext.setIPDAdjust(0.0);
-        childLM.addAreas(posIter, childContext);
-        ((InlineArea)holder).setIPD(savedIPD);
-    }
-
-    public int getStackingSize() {
-        return stackSize;
-    }
-
-    /** @see org.apache.fop.layoutmgr.LayoutManager */
-    public Area getParentArea(Area childArea) {
-        return holder;
-    }
-
-    /** 
-     * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
-     **/
-    public void addChildArea(Area childArea) {
-        holder.addChildArea(childArea);
-    }
-
-    /**
-     * Set the user agent.
-     *
-     * @param ua the user agent
-     */
-    public void setUserAgent(FOUserAgent ua) {
-        userAgent = ua;
-    }
-
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#getUserAgent()
-     */
-    public FOUserAgent getUserAgent() {
-        return userAgent;
-    }
-
-    /** @see org.apache.fop.layoutmgr.LayoutManager */
-    public void setParent(LayoutManager lm) {
-        parentLM = lm;
-    }
-
-    public LayoutManager getParent() {
-        return this.parentLM;
-    }
-
-    /** @see org.apache.fop.layoutmgr.LayoutManager */
-    public boolean isFinished() {
-        return false;
-    }
-
-    /** @see org.apache.fop.layoutmgr.LayoutManager */
-    public void setFinished(boolean isFinished) {
-        //to be done
-    }
-
-    /** @see org.apache.fop.layoutmgr.LayoutManager */
-    public void resetPosition(Position position) {
-        //to be done
-    }
-
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#createNextChildLMs
-     */
-    public boolean createNextChildLMs(int pos) {
-        return false;
-    }
-
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs
-     */
-    public List getChildLMs() {
-        List childLMs = new ArrayList(1);
-        childLMs.add(childLM);
-        return childLMs;
-    }
-
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#addChildLM
-     */
-    public void addChildLM(LayoutManager lm) {
-        if (lm == null) {
-            return;
-        }
-        lm.setParent(this);
-        childLM = (InlineLevelLayoutManager)lm;
-        log.trace(this.getClass().getName()
-                  + ": Adding child LM " + lm.getClass().getName());
-    }
-
-    /**
-     * @see org.apache.fop.layoutmgr.LayoutManager#addChildLMs
-     */
-    public void addChildLMs(List newLMs) {
-        if (newLMs == null || newLMs.size() == 0) {
-            return;
-        }
-        ListIterator iter = newLMs.listIterator();
-        while (iter.hasNext()) {
-            LayoutManager lm = (LayoutManager) iter.next();
-            addChildLM(lm);
-        }
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        LinkedList contentList = new LinkedList();
-        LinkedList returnedList;
-
-        while (!childLM.isFinished()) {
-            // get KnuthElements from childLM
-            returnedList = childLM.getNextKnuthElements(context, alignment);
-
-            if (returnedList != null) {
-                // move elements to contentList, and accumulate their size
-               KnuthElement contentElement;
-               while (returnedList.size() > 0) {
-                    contentElement = (KnuthElement)returnedList.removeFirst();
-                    stackSize += contentElement.getW();
-                    contentList.add(contentElement);
-                }
-            }
-        }
-
-        setFinished(true);
-        return contentList;
-    }
-
-    public List addALetterSpaceTo(List oldList) {
-        return oldList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-    }
-
-    public boolean applyChanges(List oldList) {
-        return false;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              /*int flaggedPenalty,*/
-                                              int alignment) {
-        return null;
-    }
-    
-    public PageSequenceLayoutManager getPSLM() {
-        return parentLM.getPSLM();
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/ExternalGraphicLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ExternalGraphicLayoutManager.java
deleted file mode 100644 (file)
index 18c3640..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-// Java
-import java.awt.geom.Rectangle2D;
-
-// FOP
-import org.apache.fop.area.inline.Image;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.Viewport;
-import org.apache.fop.datatypes.Length;
-import org.apache.fop.fo.flow.ExternalGraphic;
-
-/**
- * LayoutManager for the fo:external-graphic formatting object
- */
-public class ExternalGraphicLayoutManager extends LeafNodeLayoutManager {
-    
-    private ExternalGraphic fobj;
-
-    private int breakAfter;
-    private int breakBefore;
-    private int align;
-    private int startIndent;
-    private int endIndent;
-    private int spaceBefore;
-    private int spaceAfter;
-    private int viewWidth = -1;
-    private int viewHeight = -1;
-    private boolean clip = false;
-    private Rectangle2D placement = null;
-
-    /**
-     * Constructor
-     *
-     * @param node the fo:external-graphic formatting object that creates the area
-     */
-    public ExternalGraphicLayoutManager(ExternalGraphic node) {
-        super(node);
-        fobj = node;
-        setup();
-        InlineArea area = getExternalGraphicInlineArea();
-        setCurrentArea(area);
-        setAlignment(fobj.getVerticalAlign());
-        setLead(viewHeight);
-    }
-
-    /**
-     * Setup this image.
-     * This gets the sizes for the image and the dimensions and clipping.
-     * @todo see if can simplify property handling logic
-     */
-    private void setup() {
-        // assume lr-tb for now and just use the .optimum value of the range
-        Length ipd = fobj.getInlineProgressionDimension().getOptimum().getLength();
-        if (ipd.getEnum() != EN_AUTO) {
-            viewWidth = ipd.getValue();
-        } else {
-            ipd = fobj.getWidth();
-            if (ipd.getEnum() != EN_AUTO) {
-                viewWidth = ipd.getValue();
-            }
-        }
-        Length bpd = fobj.getBlockProgressionDimension().getOptimum().getLength();
-        if (bpd.getEnum() != EN_AUTO) {
-            viewHeight = bpd.getValue();
-        } else {
-            bpd = fobj.getHeight();
-            if (bpd.getEnum() != EN_AUTO) {
-                viewHeight = bpd.getValue();
-            }
-        }
-
-        int cwidth = -1;
-        int cheight = -1;
-        Length ch = fobj.getContentHeight();
-        if (ch.getEnum() != EN_AUTO) {
-            if (ch.getEnum() == EN_SCALE_TO_FIT) {
-                if (viewHeight != -1) {
-                    cheight = viewHeight;
-                }
-            } else {
-                cheight = ch.getValue();
-            }
-        }
-        Length cw = fobj.getContentWidth();
-        if (cw.getEnum() != EN_AUTO) {
-            if (cw.getEnum() == EN_SCALE_TO_FIT) {
-                if (viewWidth != -1) {
-                    cwidth = viewWidth;
-                }
-            } else {
-                cwidth = cw.getValue();
-            }
-        }
-
-        int scaling = fobj.getScaling();
-        if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
-            if (cwidth == -1 && cheight == -1) {
-                cwidth = fobj.getIntrinsicWidth();
-                cheight = fobj.getIntrinsicHeight();
-            } else if (cwidth == -1) {
-                cwidth = (int)(fobj.getIntrinsicWidth() * (double)cheight 
-                    / fobj.getIntrinsicHeight());
-            } else if (cheight == -1) {
-                cheight = (int)(fobj.getIntrinsicHeight() * (double)cwidth 
-                    / fobj.getIntrinsicWidth());
-            } else {
-                // adjust the larger
-                double rat1 = cwidth / fobj.getIntrinsicWidth();
-                double rat2 = cheight / fobj.getIntrinsicHeight();
-                if (rat1 < rat2) {
-                    // reduce cheight
-                    cheight = (int)(rat1 * fobj.getIntrinsicHeight());
-                } else if (rat1 > rat2) {
-                    cwidth = (int)(rat2 * fobj.getIntrinsicWidth());
-                }
-            }
-        }
-
-        if (viewWidth == -1) {
-            viewWidth = cwidth;
-        }
-        if (viewHeight == -1) {
-            viewHeight = cheight;
-        }
-
-        if (cwidth > viewWidth || cheight > viewHeight) {
-            int overflow = fobj.getOverflow();
-            if (overflow == EN_HIDDEN) {
-                clip = true;
-            } else if (overflow == EN_ERROR_IF_OVERFLOW) {
-                fobj.getLogger().error("Image: " + fobj.getURL()
-                                  + " overflows the viewport, clipping to viewport");
-                clip = true;
-            }
-        }
-
-        int xoffset = 0;
-        int yoffset = 0;
-        switch(fobj.getDisplayAlign()) {
-            case EN_BEFORE:
-            break;
-            case EN_AFTER:
-                yoffset = viewHeight - cheight;
-            break;
-            case EN_CENTER:
-                yoffset = (viewHeight - cheight) / 2;
-            break;
-            case EN_AUTO:
-            default:
-            break;
-        }
-
-        switch(fobj.getTextAlign()) {
-            case EN_CENTER:
-                xoffset = (viewWidth - cwidth) / 2;
-            break;
-            case EN_END:
-                xoffset = viewWidth - cwidth;
-            break;
-            case EN_START:
-            break;
-            case EN_JUSTIFY:
-            default:
-            break;
-        }
-        placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
-    }
-
-     /**
-      * Get the inline area for this external grpahic.
-      * This creates the image area and puts it inside a viewport.
-      *
-      * @return the viewport containing the image area
-      */
-     public InlineArea getExternalGraphicInlineArea() {
-         Image imArea = new Image(fobj.getSrc());
-         Viewport vp = new Viewport(imArea);
-         vp.setIPD(viewWidth);
-         vp.setBPD(viewHeight);
-         vp.setClip(clip);
-         vp.setContentPosition(placement);
-         vp.setOffset(0);
-
-         // Common Border, Padding, and Background Properties
-         TraitSetter.addBorders(vp, fobj.getCommonBorderPaddingBackground());
-         TraitSetter.addBackground(vp, fobj.getCommonBorderPaddingBackground());
-
-         return vp;
-     }
-     
-     protected void addId() {
-         getPSLM().addIDToPage(fobj.getId());
-     }
-}
-
index 89015813d68852a81a0107c35f45b3cd67d98651..a400078c264011619f9d06a4837f7e3b636ed01d 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.fop.layoutmgr;
 
 import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.pagination.Flow;
+import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.BlockParent;
 
diff --git a/src/java/org/apache/fop/layoutmgr/FootnoteLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FootnoteLayoutManager.java
deleted file mode 100644 (file)
index f66f261..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-
-import org.apache.fop.fo.flow.Footnote;
-
-public class FootnoteLayoutManager extends AbstractLayoutManager 
-                                   implements InlineLevelLayoutManager {
-
-    private Footnote footnote;
-    private InlineStackingLayoutManager citationLM;
-    private FootnoteBodyLayoutManager bodyLM;
-
-    /**
-     * Create a new footnote layout manager.
-     * @param node footnote to create the layout manager for
-     */
-    public FootnoteLayoutManager(Footnote node) {
-        super(node);
-        footnote = node;
-
-        // create an InlineStackingLM handling the fo:inline child of fo:footnote
-        citationLM = new InlineStackingLayoutManager(footnote.getFootnoteCitation());
-
-        // create a FootnoteBodyLM handling the fo:footnote-body child of fo:footnote
-        bodyLM = new FootnoteBodyLayoutManager(footnote.getFootnoteBody());
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        // this is the only method that must be implemented:
-        // all other methods will never be called, as the returned elements
-        // contain Positions created by the citationLM, so its methods will
-        // be called instead
-
-        // set the citationLM parent to be this LM's parent
-        citationLM.setParent(getParent());
-        bodyLM.setParent(this);
-
-        // get Knuth elements representing the footnote citation
-        LinkedList returnedList = new LinkedList();
-        while (!citationLM.isFinished()) {
-            LinkedList partialList = citationLM.getNextKnuthElements(context, alignment);
-            if (partialList != null) {
-                returnedList.addAll(partialList);
-            }
-        }
-        if (returnedList.size() == 0) {
-            //Inline part of the footnote is empty. Need to send back an auxiliary
-            //zero-width, zero-height inline box so the footnote gets painted.
-            returnedList.add(new KnuthInlineBox(0, 0, 0, 0, null, true));
-        }
-        setFinished(true);
-
-        addAnchor(returnedList);
-
-        return returnedList;
-    }
-
-    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;
-        while (citationIterator.hasPrevious() && lastBox == null) {
-            KnuthElement element = (KnuthElement) citationIterator.previous();
-            if (element instanceof KnuthInlineBox) {
-                lastBox = (KnuthInlineBox) element;
-            }
-        }
-        if (lastBox != null) {
-            lastBox.setFootnoteBodyLM(bodyLM);
-        }
-    }
-
-    public List addALetterSpaceTo(List oldList) {
-        log.warn("null implementation of addALetterSpaceTo() called!");
-        return oldList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-        log.warn("null implementation of getWordChars() called!");
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        log.warn("null implementation of hyphenate called!");
-    }
-
-    public boolean applyChanges(List oldList) {
-        log.warn("null implementation of applyChanges() called!");
-        return false;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              int alignment) {
-        log.warn("null implementation of getChangeKnuthElement() called!");
-        return null;
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/HyphContext.java b/src/java/org/apache/fop/layoutmgr/HyphContext.java
deleted file mode 100644 (file)
index 8e8e18e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-/**
- * This class is used to pass information to the getNextBreakPoss()
- * method concerning hyphenation. A reference to an instance of the
- * class is contained in the LayoutContext object passed to each
- * LayoutManager. It contains information concerning the hyphenation
- * points in a word and the how many of those have previously been
- * processed by a Layout Manager to generate size information.
- */
-public class HyphContext {
-    private int[] hyphPoints;
-    private int currentOffset = 0;
-    private int currentIndex = 0;
-
-    public HyphContext(int[] hyphPoints) {
-        this.hyphPoints = hyphPoints;
-    }
-
-    public int getNextHyphPoint() {
-        for (; currentIndex < hyphPoints.length; currentIndex++) {
-            if (hyphPoints[currentIndex] > currentOffset) {
-                return (hyphPoints[currentIndex] - currentOffset);
-            }
-        }
-        return -1; // AT END!
-    }
-
-    public boolean hasMoreHyphPoints() {
-        for (; currentIndex < hyphPoints.length; currentIndex++) {
-            if (hyphPoints[currentIndex] > currentOffset) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void updateOffset(int iCharsProcessed) {
-        currentOffset += iCharsProcessed;
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/ICLayoutManager.java b/src/java/org/apache/fop/layoutmgr/ICLayoutManager.java
deleted file mode 100644 (file)
index e03947d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-// Java
-import java.util.List;
-
-// FOP
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.fo.flow.InlineContainer;
-/**
- * This creates a single inline container area after
- * laying out the child block areas. All footnotes, floats
- * and id areas are maintained for later retrieval.
- */
-public class ICLayoutManager extends LeafNodeLayoutManager {
-    private InlineContainer fobj;
-    private List childrenLM;
-
-    public ICLayoutManager(InlineContainer node, List childLM) {
-        super(node);
-        fobj = node;
-        childrenLM = childLM;
-    }
-
-    public InlineArea get(int index) {
-        return null;
-    }
-
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/InlineLayoutManager.java
deleted file mode 100755 (executable)
index 4e28933..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-import java.util.ListIterator;
-import java.util.LinkedList;
-
-import org.apache.fop.fo.flow.InlineLevel;
-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.traits.MinOptMax;
-import org.apache.fop.traits.SpaceVal;
-
-/**
- * LayoutManager for objects which stack children in the inline direction,
- * such as Inline or Line
- */
-public class InlineLayoutManager extends InlineStackingLayoutManager 
-                                         implements InlineLevelLayoutManager {
-    private InlineLevel fobj;
-
-    private CommonMarginInline inlineProps = null;
-    private CommonBorderPaddingBackground borderProps = null;
-
-    /**
-     * Create an inline layout manager.
-     * This is used for fo's that create areas that
-     * contain inline areas.
-     *
-     * @param node the formatting object that creates the area
-     */
-    // The node should be FObjMixed
-    public InlineLayoutManager(InlineLevel node) {
-        super(node);
-        fobj = node;
-        initialize();
-    }
-    
-    private void initialize() {
-        inlineProps = fobj.getCommonMarginInline();
-        borderProps = fobj.getCommonBorderPaddingBackground();
-
-        int iPad = borderProps.getPadding(CommonBorderPaddingBackground.BEFORE, false);
-        iPad += borderProps.getBorderWidth(CommonBorderPaddingBackground.BEFORE,
-                                             false);
-        iPad += borderProps.getPadding(CommonBorderPaddingBackground.AFTER, false);
-        iPad += borderProps.getBorderWidth(CommonBorderPaddingBackground.AFTER, false);
-        extraBPD = new MinOptMax(iPad);
-    }
-
-    protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
-        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.START,
-                                           bNotFirst);
-        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.START,
-                                            bNotFirst);
-        iBP += borderProps.getPadding(CommonBorderPaddingBackground.END, bNotLast);
-        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, bNotLast);
-        return new MinOptMax(iBP);
-    }
-
-
-    protected boolean hasLeadingFence(boolean bNotFirst) {
-        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.START,
-                                           bNotFirst);
-        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.START,
-                                            bNotFirst);
-        return (iBP > 0);
-    }
-
-    protected boolean hasTrailingFence(boolean bNotLast) {
-        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.END, bNotLast);
-        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, bNotLast);
-        return (iBP > 0);
-    }
-
-    protected SpaceProperty getSpaceStart() {
-        return inlineProps.spaceStart;
-    }
-    protected SpaceProperty getSpaceEnd() {
-        return inlineProps.spaceEnd;
-    }
-    
-    protected void setTraits(boolean bNotFirst, boolean bNotLast) {
-        
-        // Add border and padding to current area and set flags (FIRST, LAST ...)
-        TraitSetter.setBorderPaddingTraits(getCurrentArea(),
-                                           borderProps, bNotFirst, bNotLast);
-
-        if (borderProps != null) {
-            TraitSetter.addBorders(getCurrentArea(), borderProps);
-            TraitSetter.addBackground(getCurrentArea(), borderProps);
-        }
-    }
-
-    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);
-            if (getSpaceStart() != null) {
-                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);
-                }
-                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 KnuthElement addALetterSpaceTo(KnuthElement element) {
-        NonLeafPosition savedPos = (NonLeafPosition) element.getPosition();
-        element.setPosition(savedPos.getPosition());
-
-        KnuthElement newElement
-            = ((InlineLevelLayoutManager)
-               element.getLayoutManager()).addALetterSpaceTo(element);
-        newElement.setPosition
-            (new NonLeafPosition(this, newElement.getPosition()));
-        element.setPosition(savedPos);
-        return newElement;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-        Position newPos = ((NonLeafPosition) pos).getPosition();
-        ((InlineLevelLayoutManager)
-         newPos.getLM()).getWordChars(sbChars, newPos);
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        Position newPos = ((NonLeafPosition) pos).getPosition();
-        ((InlineLevelLayoutManager)
-         newPos.getLM()).hyphenate(newPos, hc);
-    }
-
-    public boolean applyChanges(List oldList) {
-        // "unwrap" the Positions stored in the elements
-        ListIterator oldListIterator = oldList.listIterator();
-        KnuthElement oldElement;
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (((NonLeafPosition) oldElement.getPosition()).getPosition());
-        }
-        // reset the iterator
-        oldListIterator = oldList.listIterator();
-
-        InlineLevelLayoutManager prevLM = null;
-        InlineLevelLayoutManager currLM;
-        int fromIndex = 0;
-
-        boolean bSomethingChanged = false;
-        while(oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
-            // initialize prevLM
-            if (prevLM == null) {
-                prevLM = currLM;
-            }
-
-            if (currLM != prevLM || !oldListIterator.hasNext()) {
-                if (oldListIterator.hasNext()) {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
-                        || bSomethingChanged;
-                    prevLM = currLM;
-                    fromIndex = oldListIterator.previousIndex();
-                } else if (currLM == prevLM) {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldList.size()))
-                        || bSomethingChanged;
-                } else {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
-                        || bSomethingChanged;
-                    bSomethingChanged
-                        = currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size()))
-                        || bSomethingChanged;
-                }
-            }
-        }
-
-        // "wrap" again the Positions stored in the elements
-        oldListIterator = oldList.listIterator();
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (new NonLeafPosition(this, oldElement.getPosition()));
-        }
-        return bSomethingChanged;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, int alignment) {
-        // "unwrap" the Positions stored in the elements
-        ListIterator oldListIterator = oldList.listIterator();
-        KnuthElement oldElement;
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (((NonLeafPosition) oldElement.getPosition()).getPosition());
-        }
-        // reset the iterator
-        oldListIterator = oldList.listIterator();
-
-        KnuthElement returnedElement;
-        LinkedList returnedList = new LinkedList();
-        LinkedList returnList = new LinkedList();
-        InlineLevelLayoutManager prevLM = null;
-        InlineLevelLayoutManager currLM;
-        int fromIndex = 0;
-
-        while(oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
-            if (prevLM == null) {
-                prevLM = currLM;
-            }
-
-            if (currLM != prevLM || !oldListIterator.hasNext()) {
-                if (oldListIterator.hasNext()) {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex,
-                                          oldListIterator.previousIndex()),
-                          flaggedPenalty, alignment));
-                    prevLM = currLM;
-                    fromIndex = oldListIterator.previousIndex();
-                } else if (currLM == prevLM) {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex, oldList.size()),
-                          flaggedPenalty, alignment));
-                } else {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex,
-                                          oldListIterator.previousIndex()),
-                          flaggedPenalty, alignment));
-                    returnedList.addAll
-                        (currLM.getChangedKnuthElements
-                         (oldList.subList(oldListIterator.previousIndex(),
-                                          oldList.size()),
-                          flaggedPenalty, alignment));
-                }
-            }
-        }
-
-        // "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);
-        }
-        return returnList;
-    }*/
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/InlineLevelLayoutManager.java b/src/java/org/apache/fop/layoutmgr/InlineLevelLayoutManager.java
deleted file mode 100644 (file)
index 98d7c35..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2004-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.layoutmgr;
-
-import java.util.List;
-
-/**
- * The interface for LayoutManagers which generate inline areas
- */
-public interface InlineLevelLayoutManager extends LayoutManager {
-
-    /**
-     * Tell the LM to modify its data, adding a letter space 
-     * to the word fragment represented by the given elements,
-     * and returning the corrected elements
-     *
-     * @param oldList the elements which must be given one more letter space
-     * @return        the new elements replacing the old ones
-     */
-    List addALetterSpaceTo(List oldList);
-
-    /**
-     * Get the word chars corresponding to the given position
-     *
-     * @param sbChars the StringBuffer used to append word chars
-     * @param pos     the Position referring to the needed word chars
-     */
-    void getWordChars(StringBuffer sbChars, Position pos);
-
-    /**
-     * Tell the LM to hyphenate a word
-     *
-     * @param pos the Position referring to the word
-     * @param hc  the HyphContext storing hyphenation information
-     */
-    void hyphenate(Position pos, HyphContext hc);
-
-    /**
-     * Tell the LM to apply the changes due to hyphenation
-     *
-     * @param oldList the list of the old elements the changes refer to
-     * @return        true if the LM had to change its data, false otherwise
-     */
-    boolean applyChanges(List oldList);
-
-}
diff --git a/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java
deleted file mode 100644 (file)
index 2272d58..0000000
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import java.util.LinkedList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.HashMap;
-
-import org.apache.fop.fo.FObj;
-import org.apache.fop.fo.properties.SpaceProperty;
-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;
-
-/**
- * Class modelling the commonalities of layoutmanagers for objects
- * which stack children in the inline direction, such as Inline or
- * Line. It should not be instantiated directly.
- */
-public class InlineStackingLayoutManager extends AbstractLayoutManager 
-                                         implements InlineLevelLayoutManager {
-
-
-    private static class StackingIter extends PositionIterator {
-
-        StackingIter(Iterator parentIter) {
-            super(parentIter);
-        }
-
-        protected LayoutManager getLM(Object nextObj) {
-            return ((Position) nextObj).getLM();
-        }
-
-        protected Position getPos(Object nextObj) {
-            return ((Position) nextObj);
-        }
-    }
-
-
-    /**
-     * Size of any start or end borders and padding.
-     */
-    private MinOptMax allocIPD = new MinOptMax(0);
-
-    /**
-     * Size of border and padding in BPD (ie, before and after).
-     */
-    protected MinOptMax extraBPD;
-
-    private Area currentArea; // LineArea or InlineParent
-
-    //private BreakPoss prevBP;
-    protected LayoutContext childLC;
-
-    private LayoutManager lastChildLM = null; // Set when return last breakposs
-    private boolean bAreaCreated = false;
-
-    //private LayoutManager currentLM = null;
-
-    /** Used to store previous content IPD for each child LM. */
-    private HashMap hmPrevIPD = new HashMap();
-
-    /**
-     * Create an inline stacking layout manager.
-     * This is used for fo's that create areas that
-     * contain inline areas.
-     *
-     * @param node the formatting object that creates the area
-     */
-    protected InlineStackingLayoutManager(FObj node) {
-        super(node);
-        extraBPD = new MinOptMax(0);
-    }
-
-    /**
-     * Set the iterator.
-     *
-     * @param iter the iterator for this LM
-     */
-    public void setLMiter(ListIterator iter) {
-        childLMiter = iter;
-    }
-
-    protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
-        return new MinOptMax(0);
-    }
-
-
-    protected boolean hasLeadingFence(boolean bNotFirst) {
-        return false;
-    }
-
-    protected boolean hasTrailingFence(boolean bNotLast) {
-        return false;
-    }
-
-    protected SpaceProperty getSpaceStart() {
-        return null;
-    }
-    
-    protected SpaceProperty getSpaceEnd() {
-        return null;
-    }
-
-    /**
-     * Reset position for returning next BreakPossibility.
-     * @param prevPos a Position returned by this layout manager
-     * representing a potential break decision.
-     */
-    public void resetPosition(Position prevPos) {
-        if (prevPos != null) {
-            // ASSERT (prevPos.getLM() == this)
-            if (prevPos.getLM() != this) {
-                //getLogger().error(
-                //  "InlineStackingLayoutManager.resetPosition: " +
-                //  "LM mismatch!!!");
-            }
-            // Back up the child LM Position
-            Position childPos = prevPos.getPosition();
-            reset(childPos);
-            /*
-            if (prevBP != null
-                    && prevBP.getLayoutManager() != childPos.getLM()) {
-                childLC = null;
-            }
-            prevBP = new BreakPoss(childPos);
-            */
-        } else {
-            // Backup to start of first child layout manager
-            //prevBP = null;
-            // super.resetPosition(prevPos);
-            reset(prevPos);
-            // If any areas created, we are restarting!
-            bAreaCreated = false;
-        }
-        // Do we need to reset some context like pending or prevContent?
-        // What about prevBP?
-    }
-
-    protected MinOptMax getPrevIPD(LayoutManager lm) {
-        return (MinOptMax) hmPrevIPD.get(lm);
-    }
-
-    /**
-     * Clear the previous IPD calculation.
-     */
-    protected void clearPrevIPD() {
-        hmPrevIPD.clear();
-    }
-
-    protected InlineParent createArea() {
-        return new InlineParent();
-    }
-
-    /**
-     * 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) {
-        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;
-    }
-
-    protected void setCurrentArea(Area area) {
-        currentArea = area;
-    }
-
-    protected void setTraits(boolean bNotFirst, boolean bNotLast) {
-        
-    }
-
-    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;
-    }
-
-    // Current child layout context
-    protected LayoutContext getContext() {
-        return childLC;
-    }
-
-    protected void addSpace(Area parentArea, MinOptMax spaceRange,
-                            double dSpaceAdjust) {
-        if (spaceRange != null) {
-            int iAdjust = spaceRange.opt;
-            if (dSpaceAdjust > 0.0) {
-                // Stretch by factor
-                iAdjust += (int) ((double) (spaceRange.max
-                                          - spaceRange.opt) * dSpaceAdjust);
-            } else if (dSpaceAdjust < 0.0) {
-                // Shrink by factor
-                iAdjust += (int) ((double) (spaceRange.opt
-                                          - spaceRange.min) * dSpaceAdjust);
-            }
-            if (iAdjust != 0) {
-                //getLogger().debug("Add leading space: " + iAdjust);
-                Space ls = new Space();
-                ls.setIPD(iAdjust);
-                parentArea.addChildArea(ls);
-            }
-        }
-    }
-
-    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
-
-        ListIterator oldListIterator = oldList.listIterator();
-        KnuthElement element = null;
-        // "unwrap" the Position stored in each element of oldList
-        while (oldListIterator.hasNext()) {
-            element = (KnuthElement) oldListIterator.next();
-            element.setPosition(((NonLeafPosition)element.getPosition()).getPosition());
-        }
-
-        oldList = ((InlineLevelLayoutManager)
-                   element.getLayoutManager()).addALetterSpaceTo(oldList);
-
-        // "wrap" againg the Position stored in each element of oldList
-        oldListIterator = oldList.listIterator();
-        while (oldListIterator.hasNext()) {
-            element = (KnuthElement) oldListIterator.next();
-            element.setPosition(new NonLeafPosition(this, element.getPosition()));
-        }
-
-        return oldList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-        Position newPos = ((NonLeafPosition) pos).getPosition();
-        ((InlineLevelLayoutManager)
-         newPos.getLM()).getWordChars(sbChars, newPos);
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        Position newPos = ((NonLeafPosition) pos).getPosition();
-        ((InlineLevelLayoutManager)
-         newPos.getLM()).hyphenate(newPos, hc);
-    }
-
-    public boolean applyChanges(List oldList) {
-        // "unwrap" the Positions stored in the elements
-        ListIterator oldListIterator = oldList.listIterator();
-        KnuthElement oldElement;
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (((NonLeafPosition) oldElement.getPosition()).getPosition());
-        }
-        // reset the iterator
-        oldListIterator = oldList.listIterator();
-
-        InlineLevelLayoutManager prevLM = null;
-        InlineLevelLayoutManager currLM;
-        int fromIndex = 0;
-
-        boolean bSomethingChanged = false;
-        while(oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
-            // initialize prevLM
-            if (prevLM == null) {
-                prevLM = currLM;
-            }
-
-            if (currLM != prevLM || !oldListIterator.hasNext()) {
-                if (oldListIterator.hasNext()) {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
-                        || bSomethingChanged;
-                    prevLM = currLM;
-                    fromIndex = oldListIterator.previousIndex();
-                } else if (currLM == prevLM) {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldList.size()))
-                        || bSomethingChanged;
-                } else {
-                    bSomethingChanged
-                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
-                        || bSomethingChanged;
-                    bSomethingChanged
-                        = currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size()))
-                        || bSomethingChanged;
-                }
-            }
-        }
-
-        // "wrap" again the Positions stored in the elements
-        oldListIterator = oldList.listIterator();
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (new NonLeafPosition(this, oldElement.getPosition()));
-        }
-        return bSomethingChanged;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList, /*int flaggedPenalty,*/ int alignment) {
-        // "unwrap" the Positions stored in the elements
-        ListIterator oldListIterator = oldList.listIterator();
-        KnuthElement oldElement;
-        while (oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            oldElement.setPosition
-                (((NonLeafPosition) oldElement.getPosition()).getPosition());
-        }
-        // reset the iterator
-        oldListIterator = oldList.listIterator();
-
-        KnuthElement returnedElement;
-        LinkedList returnedList = new LinkedList();
-        LinkedList returnList = new LinkedList();
-        InlineLevelLayoutManager prevLM = null;
-        InlineLevelLayoutManager currLM;
-        int fromIndex = 0;
-
-        while(oldListIterator.hasNext()) {
-            oldElement = (KnuthElement) oldListIterator.next();
-            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
-            if (prevLM == null) {
-                prevLM = currLM;
-            }
-
-            if (currLM != prevLM || !oldListIterator.hasNext()) {
-                if (oldListIterator.hasNext()) {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex,
-                                          oldListIterator.previousIndex()),
-                          /*flaggedPenalty,*/ alignment));
-                    prevLM = currLM;
-                    fromIndex = oldListIterator.previousIndex();
-                } else if (currLM == prevLM) {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex, oldList.size()),
-                          /*flaggedPenalty,*/ alignment));
-                } else {
-                    returnedList.addAll
-                        (prevLM.getChangedKnuthElements
-                         (oldList.subList(fromIndex,
-                                          oldListIterator.previousIndex()),
-                          /*flaggedPenalty,*/ alignment));
-                    returnedList.addAll
-                        (currLM.getChangedKnuthElements
-                         (oldList.subList(oldListIterator.previousIndex(),
-                                          oldList.size()),
-                          /*flaggedPenalty,*/ alignment));
-                }
-            }
-        }
-
-        // "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);
-        }
-        return returnList;
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java b/src/java/org/apache/fop/layoutmgr/InstreamForeignObjectLM.java
deleted file mode 100644 (file)
index d19602a..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 1999-2004 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.layoutmgr;
-
-// Java
-import java.awt.geom.Rectangle2D;
-
-// FOP
-import org.apache.fop.datatypes.Length;
-import org.apache.fop.fo.XMLObj;
-import org.apache.fop.fo.flow.InstreamForeignObject;
-import org.apache.fop.area.inline.ForeignObject;
-import org.apache.fop.area.inline.Viewport;
-
-/**
- * LayoutManager for the fo:instream-foreign-object formatting object
- */
-public class InstreamForeignObjectLM extends LeafNodeLayoutManager {
-    
-    private InstreamForeignObject fobj;
-    
-    /**
-     * Constructor
-     * @param node the formatting object that creates this area
-     */
-    public InstreamForeignObjectLM(InstreamForeignObject node) {
-        super(node);
-        fobj = node;
-        Viewport areaCurrent = getInlineArea();
-        setCurrentArea(areaCurrent);
-        setAlignment(node.getVerticalAlign());
-        setLead(areaCurrent.getBPD());
-    }
-
-    /**
-     * Get the inline area created by this element.
-     *
-     * @return the viewport inline area
-     */
-    private Viewport getInlineArea() {
-        XMLObj child = (XMLObj) fobj.childNodes.get(0);
-
-        // viewport size is determined by block-progression-dimension
-        // and inline-progression-dimension
-
-        // if replaced then use height then ignore block-progression-dimension
-        //int h = this.propertyList.get("height").getLength().mvalue();
-
-        // use specified line-height then ignore dimension in height direction
-        boolean hasLH = false; //propertyList.get("line-height").getSpecifiedValue() != null;
-
-        Length len;
-
-        int bpd = -1;
-        int ipd = -1;
-        boolean bpdauto = false;
-        if (hasLH) {
-            bpd = fobj.getLineHeight().getValue();
-        } else {
-            // this property does not apply when the line-height applies
-            // isn't the block-progression-dimension always in the same
-            // direction as the line height?
-            len = fobj.getBlockProgressionDimension().getOptimum().getLength();
-            if (len.getEnum() != EN_AUTO) {
-                bpd = len.getValue();
-            } else {
-                len = fobj.getHeight();
-                if (len.getEnum() != EN_AUTO) {
-                    bpd = len.getValue();
-                }
-            }
-        }
-
-        len = fobj.getInlineProgressionDimension().getOptimum().getLength();
-        if (len.getEnum() != EN_AUTO) {
-            ipd = len.getValue();
-        } else {
-            len = fobj.getWidth();
-            if (len.getEnum() != EN_AUTO) {
-                ipd = len.getValue();
-            }
-        }
-
-        // if auto then use the intrinsic size of the content scaled
-        // to the content-height and content-width
-        int cwidth = -1;
-        int cheight = -1;
-        len = fobj.getContentWidth();
-        if (len.getEnum() != EN_AUTO) {
-            if (len.getEnum() == EN_SCALE_TO_FIT) {
-                if (ipd != -1) {
-                    cwidth = ipd;
-                }
-            } else {
-                cwidth = len.getValue();
-            }
-        }
-        len = fobj.getContentHeight();
-        if (len.getEnum() != EN_AUTO) {
-            if (len.getEnum() == EN_SCALE_TO_FIT) {
-                if (bpd != -1) {
-                    cwidth = bpd;
-                }
-            } else {
-                cheight = len.getValue();
-            }
-        }
-
-        int scaling = fobj.getScaling();
-        if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
-            if (cwidth == -1 && cheight == -1) {
-                cwidth = fobj.getIntrinsicWidth();
-                cheight = fobj.getIntrinsicHeight();
-            } else if (cwidth == -1) {
-                cwidth = (int)(fobj.getIntrinsicWidth() * (double)cheight 
-                    / fobj.getIntrinsicHeight());
-            } else if (cheight == -1) {
-                cheight = (int)(fobj.getIntrinsicHeight() * (double)cwidth 
-                    / fobj.getIntrinsicWidth());
-            } else {
-                // adjust the larger
-                double rat1 = cwidth / fobj.getIntrinsicWidth();
-                double rat2 = cheight / fobj.getIntrinsicHeight();
-                if (rat1 < rat2) {
-                    // reduce cheight
-                    cheight = (int)(rat1 * fobj.getIntrinsicHeight());
-                } else if (rat1 > rat2) {
-                    cwidth = (int)(rat2 * fobj.getIntrinsicWidth());
-                }
-            }
-        }
-
-        if (ipd == -1) {
-            ipd = cwidth;
-        }
-        if (bpd == -1) {
-            bpd = cheight;
-        }
-
-        boolean clip = false;
-        if (cwidth > ipd || cheight > bpd) {
-            int overflow = fobj.getOverflow();
-            if (overflow == EN_HIDDEN) {
-                clip = true;
-            } else if (overflow == EN_ERROR_IF_OVERFLOW) {
-                fobj.getLogger().error("Instream foreign object overflows the viewport: clipping");
-                clip = true;
-            }
-        }
-
-        int xoffset = fobj.computeXOffset(ipd, cwidth);
-        int yoffset = fobj.computeYOffset(bpd, cheight);
-
-        Rectangle2D placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
-
-        org.w3c.dom.Document doc = child.getDOMDocument();
-        String ns = child.getDocumentNamespace();
-
-        //fobj.childNodes = null; This is bad for i-f-o in static-content!!!!!
-        ForeignObject foreign = new ForeignObject(doc, ns);
-
-        Viewport vp = new Viewport(foreign);
-        vp.setIPD(ipd);
-        vp.setBPD(bpd);
-        vp.setContentPosition(placement);
-        vp.setClip(clip);
-        vp.setOffset(0);
-
-        // Common Border, Padding, and Background Properties
-        TraitSetter.addBorders(vp, fobj.getCommonBorderPaddingBackground());
-        TraitSetter.addBackground(vp, fobj.getCommonBorderPaddingBackground());
-
-        return vp;
-    }
-    
-    /**
-     * @see org.apache.fop.layoutmgr.LeafNodeLayoutManager#addId()
-     */
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java b/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java
deleted file mode 100644 (file)
index 79d178c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2004-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.layoutmgr;
-
-public class KnuthInlineBox extends KnuthBox {
-    
-    private int lead;
-    private int total;
-    private int middle;
-    private FootnoteBodyLayoutManager footnoteBodyLM = null;
-
-    /**
-     * Create a new KnuthBox.
-     *
-     * @param w    the width of this box
-     * @param l    the height of this box above the main baseline
-     * @param t    the total height of this box
-     * @param m    the height of this box above and below the middle baseline
-     * @param pos  the Position stored in this box
-     * @param bAux is this box auxiliary?
-     */
-    public KnuthInlineBox(int w, int l, int t, int m, Position pos, boolean bAux) {
-        super(w, pos, bAux);
-        lead = l;
-        total = t;
-        middle = m;
-    }
-
-    /**
-     * @return the height of this box above the main baseline.
-     */
-    public int getLead() {
-        return lead;
-    }
-
-    /**
-     * @return the total height of this box.
-     */
-    public int getTotal() {
-        return total;
-    }
-
-    /**
-     * @return the height of this box above and below the middle baseline.
-     */
-    public int getMiddle() {
-        return middle;
-    }
-
-    /**
-     * @param fblm the FootnoteBodyLM this box must hold a reference to
-     */
-    public void setFootnoteBodyLM(FootnoteBodyLayoutManager fblm) {
-        footnoteBodyLM = fblm;
-    }
-
-    /**
-     * @return the FootnoteBodyLM this box holds a reference to
-     */
-    public FootnoteBodyLayoutManager getFootnoteBodyLM() {
-        return footnoteBodyLM;
-    }
-
-    /**
-     * @return true if this box holds a reference to a FootnoteBodyLM
-     */
-    public boolean isAnchor() {
-        return (footnoteBodyLM != null);
-    }
-    
-    
-    /** @see java.lang.Object#toString() */
-    public String toString() {
-        StringBuffer sb = new StringBuffer(super.toString());
-        sb.append(" lead=").append(lead);
-        sb.append(" total=").append(total);
-        sb.append(" middle=").append(middle);
-        return sb.toString();
-    }
-}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthParagraph.java b/src/java/org/apache/fop/layoutmgr/KnuthParagraph.java
deleted file mode 100644 (file)
index cf08b63..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Copyright 2004-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.layoutmgr;
-
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.apache.fop.traits.MinOptMax;
-
-/**
- * A knuth paragraph
- *
- * The set is sorted into lines indexed into activeLines.
- * The nodes in each line is linked together in a single linked list by the 
- * KnuthNode.next field. The activeLines array contains a link to the head of
- * the linked list in index 'line*2' and a link to the tail at index 'line*2+1'.
- * <p>
- * The set of active nodes can be traversed by 
- * <pre>
- * for (int line = startLine; line < endLine; line++) {
- *     for (KnuthNode node = getNode(line); node != null; node = node.next) {
- *         // Do something with 'node'
- *     }
- * }
- * </pre> 
- */
-public class KnuthParagraph {
-    // parameters of Knuth's algorithm:
-    // penalty value for flagged penalties
-    private int flaggedPenalty = 50;
-    // demerit for consecutive lines ending at flagged penalties
-    private int repeatedFlaggedDemerit = 50;
-    // demerit for consecutive lines belonging to incompatible fitness classes 
-    private int incompatibleFitnessDemerit = 50;
-    // suggested modification to the "optimum" number of lines
-    private int looseness = 0;
-
-    /**
-     * The threshold for considering breaks to be acceptable.
-     */
-    private double threshold;
-
-    /**
-     * The paragraph of KnuthElements.
-     */
-    private List par;
-    
-    /**
-     * The width of a line.
-     */
-    private int lineWidth = 0;
-    private boolean force =  false;
-
-    private KnuthNode lastTooLong;
-    private KnuthNode lastTooShort;
-    private KnuthNode lastDeactivated;
-
-    /**
-     * The set of active nodes.
-     */
-    private KnuthNode[] activeLines;
-    
-    /**
-     * The number of active nodes.
-     */
-    private int activeNodeCount;
-    
-    /**
-     * The lowest available line in the set of active nodes.
-     */
-    private int startLine = 0;
-
-    /**
-     * The highest + 1 available line in the set of active nodes.
-     */
-    private int endLine = 0;
-
-    /**
-     * The total width of all elements handled so far.
-     */
-    private int totalWidth;
-
-    /**
-     * The total stretch of all elements handled so far.
-     */
-    private int totalStretch = 0;
-
-    /**
-     * The total shrink of all elements handled so far.
-     */
-    private int totalShrink = 0;
-
-    private BestRecords best;
-    private KnuthNode[] positions;
-    
-    private static final int INFINITE_RATIO = 1000;
-    
-    protected static Log log = LogFactory.getLog(KnuthParagraph.class);
-    
-    public KnuthParagraph(List par) {
-        this.best = new BestRecords();
-        this.par = par;
-    }
-
-
-    // this class represent a feasible breaking point
-    private class KnuthNode {
-        // index of the breakpoint represented by this node
-        public int position;
-
-        // number of the line ending at this breakpoint
-        public int line;
-
-        // fitness class of the line ending at his breakpoint
-        public int fitness;
-
-        // accumulated width of the KnuthElements
-        public int totalWidth;
-
-        public int totalStretch;
-
-        public int totalShrink;
-
-        // adjustment ratio if the line ends at this breakpoint
-        public double adjustRatio;
-
-        // difference between target and actual line width
-        public int difference;
-
-        // minimum total demerits up to this breakpoint
-        public double totalDemerits;
-
-        // best node for the preceding breakpoint
-        public KnuthNode previous;
-
-        // Next possible node in the same line 
-        public KnuthNode next;
-
-        
-        public KnuthNode(int position, int line, int fitness,
-                         int totalWidth, int totalStretch, int totalShrink,
-                         double adjustRatio, int difference,
-                         double totalDemerits, KnuthNode previous) {
-            this.position = position;
-            this.line = line;
-            this.fitness = fitness;
-            this.totalWidth = totalWidth;
-            this.totalStretch = totalStretch;
-            this.totalShrink = totalShrink;
-            this.adjustRatio = adjustRatio;
-            this.difference = difference;
-            this.totalDemerits = totalDemerits;
-            this.previous = previous;
-        }
-
-        public String toString() {
-            return "<KnuthNode at " + position + " " +
-            totalWidth + "+" + totalStretch + "-" + totalShrink +
-            " line:" + line +
-            " prev:" + (previous != null ? previous.position : -1) +
-            " dem:" + totalDemerits +
-            ">"; 
-        }
-    }
-    
-    // this class stores information about how the nodes
-    // which could start a line
-    // ending at the current element
-    private class BestRecords {
-        private static final double INFINITE_DEMERITS = Double.POSITIVE_INFINITY;
-
-        private double bestDemerits[] = new double[4];
-        private KnuthNode bestNode[] = new KnuthNode[4];
-        private double bestAdjust[] = new double[4];
-        private int bestDifference[] = new int[4];
-        private int bestIndex = -1;
-
-        public BestRecords() {
-            reset();
-        }
-
-        public void addRecord(double demerits, KnuthNode node, double adjust,
-                              int difference, int fitness) {
-            if (demerits > bestDemerits[fitness]) {
-                log.error("New demerits value greter than the old one");
-            }
-            bestDemerits[fitness] = demerits;
-            bestNode[fitness] = node;
-            bestAdjust[fitness] = adjust;
-            bestDifference[fitness] = difference;
-            if (bestIndex == -1 || demerits < bestDemerits[bestIndex]) {
-                bestIndex = fitness;
-            }
-        }
-
-        public boolean hasRecords() {
-            return (bestIndex != -1);
-        }
-
-        public boolean notInfiniteDemerits(int fitness) {
-            return (bestDemerits[fitness] != INFINITE_DEMERITS);
-        }
-
-        public double getDemerits(int fitness) {
-            return bestDemerits[fitness];
-        }
-
-        public KnuthNode getNode(int fitness) {
-            return bestNode[fitness];
-        }
-
-        public double getAdjust(int fitness) {
-            return bestAdjust[fitness];
-        }
-
-        public int getDifference(int fitness) {
-            return bestDifference[fitness];
-        }
-
-        public double getMinDemerits() {
-            if (bestIndex != -1) {
-                return getDemerits(bestIndex);
-            } else {
-                // anyway, this should never happen
-                return INFINITE_DEMERITS;
-            }
-        }
-        
-        public void reset() {
-            bestDemerits[0] = INFINITE_DEMERITS;
-            bestDemerits[1] = INFINITE_DEMERITS;
-            bestDemerits[2] = INFINITE_DEMERITS;
-            bestDemerits[3] = INFINITE_DEMERITS;
-            bestIndex = -1;
-        }
-    }
-
-    public int findBreakPoints(int lineWidth, double threshold, boolean force) {
-        this.lineWidth = lineWidth;
-        this.totalWidth = 0;
-        this.totalStretch = 0;
-        this.totalShrink = 0;
-        this.threshold = threshold;
-        this.force = force;
-        
-        activeLines = new KnuthNode[20];
-        addNode(0, new KnuthNode(0, 0, 1, 0, 0, 0, 0, 0, 0, null));
-        
-        boolean bForced = false;
-
-        // previous element in the paragraph is a KnuthBox
-        boolean previousIsBox = false;
-
-        if (log.isTraceEnabled()) {
-            log.trace("Looping over " + par.size() + " box objects");
-        }
-
-        KnuthNode lastForced = getNode(0);
-        
-        // main loop
-        for (int i = 0; i < par.size(); i++) {
-            KnuthElement element = getElement(i);
-            if (element.isBox()) {
-                // a KnuthBox object is not a legal line break
-                totalWidth += element.getW();
-                previousIsBox = true;
-            } else if (element.isGlue()) {
-                // a KnuthGlue object is a legal line break
-                // only if the previous object is a KnuthBox
-                if (previousIsBox) {
-                    considerLegalBreak(element, i);
-                }
-                totalWidth += element.getW();
-                totalStretch += element.getY();
-                totalShrink += element.getZ();
-                previousIsBox = false;
-            } else {
-                // a KnuthPenalty is a legal line break
-                // only if its penalty is not infinite
-                if (element.getP() < KnuthElement.INFINITE) {
-                    considerLegalBreak(element, i);
-                }
-                previousIsBox = false;
-            }
-            if (activeNodeCount == 0) {
-                if (!force) {
-                    log.debug("Could not find a set of breaking points " + threshold);
-                    return 0;
-                }
-                /*
-                if (lastForced != null && lastForced.position == lastDeactivated.position) {
-                    lastForced = lastTooShort != null ? lastTooShort : lastTooLong;
-                } else {
-                    lastForced = lastDeactivated;
-                }
-                */
-                if (lastTooShort == null || lastForced.position == lastTooShort.position) {
-                    lastForced = lastTooLong;
-                } else {
-                    lastForced = lastTooShort;
-                }
-
-                log.debug("Restarting at node " + lastForced);
-                lastForced.totalDemerits = 0;
-                addNode(lastForced.line, lastForced);
-                i = lastForced.position;
-                startLine = lastForced.line;
-                endLine = startLine + 1;
-                totalWidth = lastForced.totalWidth;
-                totalStretch = lastForced.totalStretch;
-                totalShrink = lastForced.totalShrink;
-                lastTooShort = lastTooLong = null;
-            }
-        }
-        if (log.isTraceEnabled()) {
-            log.trace("Main loop completed " + activeNodeCount);
-            log.trace("Active nodes=" + toString(""));
-        }
-
-        // there is at least one set of breaking points
-        // choose the active node with fewest total demerits
-        KnuthNode bestActiveNode = findBestNode();
-        int line = bestActiveNode.line;
-/*
-        if (looseness != 0) {
-            // choose the appropriate active node
-            int s = 0;
-            double bestDemerits = 0;
-            for (int i = 0; i < activeList.size(); i++) {
-                KnuthNode node = getNode(i);
-                int delta = node.line - line;
-                if (looseness <= delta && delta < s
-                    || s < delta && delta <= looseness) {
-                    s = delta;
-                    bestActiveNode = node;
-                    bestDemerits = node.totalDemerits;
-                } else if (delta == s
-                           && node.totalDemerits < bestDemerits) {
-                    bestActiveNode = node;
-                    bestDemerits = node.totalDemerits;
-                }
-            }
-            line = bestActiveNode.line;
-        }
-*/
-        // Reverse the list of nodes from bestActiveNode.
-        positions = new KnuthNode[line];
-        // use the chosen node to determine the optimum breakpoints
-        for (int i = line - 1; i >= 0; i--) {
-            positions[i] = bestActiveNode;
-            bestActiveNode = bestActiveNode.previous;
-        }
-        activeLines = null;
-        return positions.length;
-    }
-
-    private void considerLegalBreak(KnuthElement element, int elementIdx) {
-
-        if (log.isTraceEnabled()) {
-            log.trace("Feasible breakpoint at " + par.indexOf(element) + " " + totalWidth + "+" + totalStretch + "-" + totalShrink);
-            log.trace("\tCurrent active node list: " + activeNodeCount + " " + this.toString("\t"));
-        }
-
-        lastDeactivated = null;
-        lastTooLong = null;
-        for (int line = startLine; line < endLine; line++) {
-            for (KnuthNode node = getNode(line); node != null; node = node.next) {
-                if (node.position == elementIdx) {
-                    continue;
-                }
-                int difference = computeDifference(node, element);
-                double r = computeAdjustmentRatio(node, difference);
-                if (log.isTraceEnabled()) {
-                    log.trace("\tr=" + r);
-                    log.trace("\tline=" + line);
-                }
-                
-                // The line would be too long.
-                if (r < -1 || element.isForcedBreak()) {
-                    // Deactivate node.
-                    if (log.isTraceEnabled()) {
-                        log.trace("Removing " + node);
-                    }
-                    removeNode(line, node);
-                    lastDeactivated = compareNodes(lastDeactivated, node);
-                }
-    
-                // The line is within the available shrink and the threshold.
-                if (r >= -1 && r <= threshold) {
-                    int fitnessClass = computeFitness(r);
-                    double demerits = computeDemerits(node, element, fitnessClass, r);
-    
-                    if (log.isTraceEnabled()) {
-                        log.trace("\tDemerits=" + demerits);
-                        log.trace("\tFitness class=" + fitnessClass);
-                    }
-    
-                    if (demerits < best.getDemerits(fitnessClass)) {
-                        // updates best demerits data
-                        best.addRecord(demerits, node, r, difference, fitnessClass);
-                    }
-                }
-                
-                // The line is way too short, but we are in forcing mode, so a node is
-                // calculated and stored in lastValidNode.
-                if (force && (r <= -1 || r > threshold)) {
-                    int fitnessClass = computeFitness(r);
-                    double demerits = computeDemerits(node, element, fitnessClass, r);
-                    if (r <= -1) {
-                        if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
-                            lastTooLong = new KnuthNode(elementIdx, line + 1, fitnessClass,
-                                    totalWidth, totalStretch, totalShrink,
-                                    r, difference, demerits, node);
-                            if (log.isTraceEnabled()) {
-                                log.trace("Picking tooLong " + lastTooLong);
-                            }
-                        }
-                    } else {
-                        if (lastTooShort == null || demerits <= lastTooShort.totalDemerits) {
-                            lastTooShort = new KnuthNode(elementIdx, line + 1, fitnessClass,
-                                    totalWidth, totalStretch, totalShrink,
-                                    r, difference, demerits, node);
-                            if (log.isTraceEnabled()) {
-                                log.trace("Picking tooShort " + lastTooShort);
-                            }
-                        }
-                    }
-                }
-            }
-            addBreaks(line, elementIdx);
-        }
-    }
-
-    
-    private void addBreaks(int line, int elementIdx) {
-        if (!best.hasRecords()) {
-            return;
-        }
-
-        int newWidth = totalWidth;
-        int newStretch = totalStretch;
-        int newShrink = totalShrink;
-
-        for (int i = elementIdx; i < par.size(); i++) {
-            KnuthElement tempElement = getElement(i);
-            if (tempElement.isBox()) {
-                break;
-            } else if (tempElement.isGlue()) {
-                newWidth += tempElement.getW();
-                newStretch += tempElement.getY();
-                newShrink += tempElement.getZ();
-            } else if (tempElement.isForcedBreak() && i != elementIdx) {
-                break;
-            }
-        }
-
-        // add nodes to the active nodes list
-        double minimumDemerits = best.getMinDemerits() + incompatibleFitnessDemerit;
-        for (int i = 0; i <= 3; i++) {
-            if (best.notInfiniteDemerits(i) && best.getDemerits(i) <= minimumDemerits) {
-                // the nodes in activeList must be ordered
-                // by line number and position;
-                if (log.isTraceEnabled()) {
-                    log.trace("\tInsert new break in list of " + activeNodeCount);
-                }
-                KnuthNode newNode = new KnuthNode(elementIdx, line + 1, i,
-                                   newWidth, newStretch, newShrink,
-                                   best.getAdjust(i),
-                                   best.getDifference(i),
-                                   best.getDemerits(i),
-                                   best.getNode(i));
-                addNode(line + 1, newNode);
-            }
-        }
-        best.reset();
-    }
-
-    /**
-     * Return the difference between the line width and the width of the break that
-     * ends in 'element'.
-     * @param activeNode
-     * @param element
-     * @return The difference in width. Positive numbers mean extra space in the line,
-     * negative number that the line overflows. 
-     */
-    private int computeDifference(KnuthNode activeNode, KnuthElement element) {
-        // compute the adjustment ratio
-        int actualWidth = totalWidth - activeNode.totalWidth;
-        if (element.isPenalty()) {
-            actualWidth += element.getW();
-        }
-        return lineWidth - actualWidth;
-    }
-
-    /**
-     * Return the adjust ration needed to make up for the difference. A ration of 
-     * <ul>
-     *    <li>0 means that the break has the exact right width</li>
-     *    <li>&gt;= -1 && &lt; 0  means that the break is to wider than the line, 
-     *        but within the minimim values of the glues.</li> 
-     *    <li>&gt;0 && &lt 1 means that the break is smaller than the line width, 
-     *        but within the maximum values of the glues.</li>
-     *    <li>&gt 1 means that the break is too small to make up for the glues.</li> 
-     * </ul>
-     * @param activeNode
-     * @param difference
-     * @return The ration.
-     */
-    private double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
-        // compute the adjustment ratio
-        if (difference > 0) {
-            int maxAdjustment = totalStretch - activeNode.totalStretch;
-            if (maxAdjustment > 0) {
-                return (double) difference / maxAdjustment;
-            } else {
-                return INFINITE_RATIO;
-            }
-        } else if (difference < 0) {
-            int maxAdjustment = totalShrink - activeNode.totalShrink;
-            if (maxAdjustment > 0) {
-                return (double) difference / maxAdjustment;
-            } else {
-                return -INFINITE_RATIO;
-            }
-        } else {
-            return 0;
-        }
-    }
-    
-    /**
-     * Figure out the fitness class of this line (tight, loose,
-     * very tight or very loose).
-     * @param r
-     * @return
-     */
-    private int computeFitness(double r) {
-        int newFitnessClass;
-        if (r < -0.5) {
-            return 0;
-        } else if (r <= 0.5) {
-            return 1;
-        } else if (r <= 1) {
-            return 2;
-        } else {
-            return 3;
-        }
-    }
-
-    /**
-     * Find and return the KnuthNode in the active set of nodes with the 
-     * lowest demerit.
-     */
-    private KnuthNode findBestNode() {
-        // choose the active node with fewest total demerits
-        KnuthNode bestActiveNode = null;
-        for (int i = startLine; i < endLine; i++) {
-            for (KnuthNode node = getNode(i); node != null; node = node.next) {
-                bestActiveNode = compareNodes(bestActiveNode, node);
-            }
-        }
-        if (log.isTraceEnabled()) {
-            log.trace("Best demerits " + bestActiveNode.totalDemerits + " for paragraph size " + par.size());
-        }
-        return bestActiveNode;
-    }
-    
-    /**
-     * Compare two KnuthNodes and return the node with the least demerit. 
-     * @param node1 The first knuth node.
-     * @param node2 The other knuth node.
-     * @return
-     */
-    private KnuthNode compareNodes(KnuthNode node1, KnuthNode node2) {
-        if (node1 == null || node2.position > node1.position) {
-            return node2;
-        }
-        if (node2.position == node1.position) {
-            if (node2.totalDemerits < node1.totalDemerits) {
-                return node2;
-            }
-        }
-        return node1;
-    }
-
-    private double computeDemerits(KnuthNode activeNode, KnuthElement element, 
-                                  int fitnessClass, double r) {
-        double demerits = 0;
-        // compute demerits
-        double f = Math.abs(r);
-        f = 1 + 100 * f * f * f;
-        if (element.isPenalty() && element.getP() >= 0) {
-            f += element.getP();
-            demerits = f * f;
-        } else if (element.isPenalty() && !element.isForcedBreak()) {
-            double penalty = element.getP();
-            demerits = f * f - penalty * penalty;
-        } else {
-            demerits = f * f;
-        }
-    
-        if (element.isPenalty() && ((KnuthPenalty) element).isFlagged()
-            && getElement(activeNode.position).isPenalty()
-            && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) {
-            // add demerit for consecutive breaks at flagged penalties
-            demerits += repeatedFlaggedDemerit;
-        }
-        if (Math.abs(fitnessClass - activeNode.fitness) > 1) {
-            // add demerit for consecutive breaks
-            // with very different fitness classes
-            demerits += incompatibleFitnessDemerit;
-        }
-        demerits += activeNode.totalDemerits;
-        return demerits;
-    }
-
-    /**
-     * Return the element at index idx in the paragraph.
-     * @param idx index of the element.
-     * @return
-     */
-    private KnuthElement getElement(int idx) {
-        return (KnuthElement) par.get(idx);
-    }
-
-    /**
-     * Add a KnuthNode at the end of line 'line'. 
-     * If this is the first node in the line, adjust endLine accordingly.
-     * @param line
-     * @param node
-     */
-    private void addNode(int line, KnuthNode node) {
-        int headIdx = line * 2;
-        if (headIdx >= activeLines.length) {
-            KnuthNode[] oldList = activeLines;
-            activeLines = new KnuthNode[headIdx + headIdx];
-            System.arraycopy(oldList, 0, activeLines, 0, oldList.length);
-        }
-        node.next = null;
-        if (activeLines[headIdx + 1] != null) {
-            activeLines[headIdx + 1].next = node;
-        } else {
-            activeLines[headIdx] = node;
-            endLine = line+1;
-        }
-        activeLines[headIdx + 1] = node;
-        activeNodeCount++;
-    }
-
-    /**
-     * Remove the first node in line 'line'. If the line then becomes empty, adjust the
-     * startLine accordingly.
-     * @param line
-     * @param node
-     */
-    private void removeNode(int line, KnuthNode node) {
-        KnuthNode n = getNode(line);
-        if (n != node) {
-            log.error("Should be first");
-        } else {
-            activeLines[line*2] = node.next;
-            if (node.next == null) {
-                activeLines[line*2+1] = null;
-            }
-            while (startLine < endLine && getNode(startLine) == null) {
-                startLine++;
-            }
-        }
-        activeNodeCount--;
-    }
-
-    private KnuthNode getNode(int line) {
-        return activeLines[line * 2];
-    }
-
-    /**
-     * Return true if the position 'idx' is a legal breakpoint.
-     * @param idx
-     * @return
-     */
-    private boolean isLegalBreakpoint(int idx) {
-        KnuthElement elm = getElement(idx);
-        if (elm.isPenalty() && elm.getP() != KnuthElement.INFINITE) {
-            return true;
-        } else if (idx > 0 && elm.isGlue() && getElement(idx-1).isBox()) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-    
-    public int getDifference(int line) {
-        return positions[line].difference;
-    }
-
-    public double getAdjustRatio(int line) {
-        return positions[line].adjustRatio;
-    }
-
-    public int getStart(int line) {
-        KnuthNode previous = positions[line].previous;
-        return line == 0 ? 0 : previous.position + 1; 
-    }
-
-    public int getEnd(int line) {
-        return positions[line].position;
-    }
-
-    /**
-     * Return a string representation of a MinOptMax in the form of a 
-     * "width+stretch-shrink". Useful only for debugging.
-     * @param mom
-     * @return 
-     */
-    private static String width(MinOptMax mom) {
-        return mom.opt + "+" + (mom.max - mom.opt) + "-" + (mom.opt - mom.min); 
-
-    }
-
-    public String toString(String prepend) {
-        StringBuffer sb = new StringBuffer();
-        sb.append("[\n");
-        for (int i = startLine; i < endLine; i++) {
-            for (KnuthNode node = getNode(i); node != null; node = node.next) {
-                sb.append(prepend + "\t" + node + ",\n");
-            }
-        }
-        sb.append(prepend + "]");
-        return sb.toString();
-    }
-}
\ No newline at end of file
index 3703502b060f61671f831ea73b77b764872d99e3..2d3323625996939646e24ce65f148794b87b432e 100644 (file)
@@ -19,6 +19,7 @@
 package org.apache.fop.layoutmgr;
 
 import org.apache.fop.fo.Constants;
+import org.apache.fop.layoutmgr.inline.HyphContext;
 import org.apache.fop.traits.MinOptMax;
 
 
index 8395e339a9d7cf3644091169a76dde74d288d54b..84663dd84853c6796455a750d975610120e76ccd 100644 (file)
@@ -61,6 +61,20 @@ import org.apache.fop.fo.pagination.StaticContent;
 import org.apache.fop.fo.pagination.Title;
 import org.apache.fop.area.AreaTreeHandler;
 
+import org.apache.fop.layoutmgr.inline.BasicLinkLayoutManager;
+import org.apache.fop.layoutmgr.inline.BidiLayoutManager;
+import org.apache.fop.layoutmgr.inline.CharacterLayoutManager;
+import org.apache.fop.layoutmgr.inline.ExternalGraphicLayoutManager;
+import org.apache.fop.layoutmgr.inline.FootnoteLayoutManager;
+import org.apache.fop.layoutmgr.inline.ICLayoutManager;
+import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
+import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
+import org.apache.fop.layoutmgr.inline.InstreamForeignObjectLM;
+import org.apache.fop.layoutmgr.inline.LeaderLayoutManager;
+import org.apache.fop.layoutmgr.inline.PageNumberCitationLayoutManager;
+import org.apache.fop.layoutmgr.inline.PageNumberLayoutManager;
+import org.apache.fop.layoutmgr.inline.TextLayoutManager;
+import org.apache.fop.layoutmgr.inline.WrapperLayoutManager;
 import org.apache.fop.layoutmgr.list.ListBlockLayoutManager;
 import org.apache.fop.layoutmgr.list.ListItemLayoutManager;
 import org.apache.fop.layoutmgr.table.TableLayoutManager;
diff --git a/src/java/org/apache/fop/layoutmgr/LeaderLayoutManager.java b/src/java/org/apache/fop/layoutmgr/LeaderLayoutManager.java
deleted file mode 100644 (file)
index fc25ea5..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.FilledArea;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.Space;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.datatypes.PercentBase;
-import org.apache.fop.fo.flow.Leader;
-import org.apache.fop.fonts.Font;
-import org.apache.fop.traits.MinOptMax;
-
-import java.util.List;
-import java.util.LinkedList;
-
-/**
- * LayoutManager for the fo:leader formatting object
- */
-public class LeaderLayoutManager extends LeafNodeLayoutManager {
-    private Leader fobj;
-    Font font = null;
-    
-    private LinkedList contentList = null;
-    private ContentLayoutManager clm = null;
-
-    /**
-     * Constructor
-     *
-     * @param node the formatting object that creates this area
-     * @todo better null checking of font object
-     */
-    public LeaderLayoutManager(Leader node) {
-        super(node);
-        fobj = node;
-        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
-        // the property leader-alignment does not affect vertical positioning
-        // (see section 7.21.1 in the XSL Recommendation)
-        // setAlignment(node.getLeaderAlignment());
-        setAlignment(fobj.getVerticalAlign());
-    }
-
-    public InlineArea get(LayoutContext context) {
-        return getLeaderInlineArea();
-    }
-
-    protected MinOptMax getAllocationIPD(int refIPD) {
-        return getLeaderAllocIPD(refIPD);
-    }
-
-    private MinOptMax getLeaderAllocIPD(int ipd) {
-        // length of the leader
-        fobj.setLayoutDimension(PercentBase.BLOCK_IPD, ipd);
-        int opt = fobj.getLeaderLength().getOptimum().getLength().getValue();
-        int min = fobj.getLeaderLength().getMinimum().getLength().getValue();
-        int max = fobj.getLeaderLength().getMaximum().getLength().getValue();
-        return new MinOptMax(min, opt, max);
-    }
-
-    private InlineArea getLeaderInlineArea() {
-        InlineArea leaderArea = null;
-
-        if (fobj.getLeaderPattern() == EN_RULE) {
-            org.apache.fop.area.inline.Leader leader = 
-                new org.apache.fop.area.inline.Leader();
-            leader.setRuleStyle(fobj.getRuleStyle());
-            leader.setRuleThickness(fobj.getRuleThickness().getValue());
-            leaderArea = leader;
-        } else if (fobj.getLeaderPattern() == EN_SPACE) {
-            leaderArea = new Space();
-        } else if (fobj.getLeaderPattern() == EN_DOTS) {
-            TextArea t = new TextArea();
-            char dot = '.'; // userAgent.getLeaderDotCharacter();
-
-            t.setTextArea("" + dot);
-            t.setIPD(font.getCharWidth(dot));
-            t.addTrait(Trait.FONT_NAME, font.getFontName());
-            t.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize()));
-            int width = font.getCharWidth(dot);
-            Space spacer = null;
-            if (fobj.getLeaderPatternWidth().getValue() > width) {
-                spacer = new Space();
-                spacer.setIPD(fobj.getLeaderPatternWidth().getValue() - width);
-                width = fobj.getLeaderPatternWidth().getValue();
-            }
-            FilledArea fa = new FilledArea();
-            fa.setUnitWidth(width);
-            fa.addChildArea(t);
-            if (spacer != null) {
-                fa.addChildArea(spacer);
-            }
-            fa.setBPD(font.getAscender());
-
-            leaderArea = fa;
-        } else if (fobj.getLeaderPattern() == EN_USECONTENT) {
-            if (fobj.getChildNodes() == null) {
-                fobj.getLogger().error("Leader use-content with no content");
-                return null;
-            }
-
-            // child FOs are assigned to the InlineStackingLM
-            fobjIter = null;
-            
-            // get breaks then add areas to FilledArea
-            FilledArea fa = new FilledArea();
-
-            clm = new ContentLayoutManager(fa, this);
-            clm.setUserAgent(fobj.getUserAgent());
-            addChildLM(clm);
-
-            InlineLayoutManager lm;
-            lm = new InlineLayoutManager(fobj);
-            clm.addChildLM(lm);
-
-            contentList = clm.getNextKnuthElements(new LayoutContext(0), 0);
-            int width = clm.getStackingSize();
-            Space spacer = null;
-            if (fobj.getLeaderPatternWidth().getValue() > width) {
-                spacer = new Space();
-                spacer.setIPD(fobj.getLeaderPatternWidth().getValue() - width);
-                width = fobj.getLeaderPatternWidth().getValue();
-            }
-            fa.setUnitWidth(width);
-            if (spacer != null) {
-                fa.addChildArea(spacer);
-            }
-            leaderArea = fa;
-        }
-        return leaderArea;
-     }
-
-    protected void offsetArea(InlineArea area, LayoutContext context) {
-        int pattern = fobj.getLeaderPattern();
-        int bpd = area.getBPD();
-
-        switch (pattern) {
-            case EN_RULE: 
-                switch (verticalAlignment) {
-                    case EN_TOP:
-                        area.setOffset(0);
-                    break;
-                    case EN_MIDDLE:
-                        area.setOffset(context.getMiddleBaseline() - bpd / 2);
-                    break;
-                    case EN_BOTTOM:
-                        area.setOffset(context.getLineHeight() - bpd);
-                    break;
-                    case EN_BASELINE: // fall through
-                    default:
-                        area.setOffset(context.getBaseline() - bpd);
-                    break;
-                }
-            break;
-            case EN_DOTS: 
-                switch (verticalAlignment) {
-                    case EN_TOP:
-                        area.setOffset(0);
-                    break;
-                    case EN_MIDDLE:
-                        area.setOffset(context.getMiddleBaseline());
-                    break;
-                    case EN_BOTTOM:
-                        area.setOffset(context.getLineHeight() - bpd + font.getAscender());
-                    break;
-                    case EN_BASELINE: // fall through
-                    default:
-                        area.setOffset(context.getBaseline());
-                    break;
-                }
-            break;
-            case EN_SPACE: 
-                // nothing to do
-            break;
-            case EN_USECONTENT: 
-                switch (verticalAlignment) {
-                    case EN_TOP:
-                        area.setOffset(0);
-                    break;
-                    case EN_MIDDLE:
-                        area.setOffset(context.getMiddleBaseline());
-                    break;
-                    case EN_BOTTOM:
-                        area.setOffset(context.getLineHeight() - bpd);
-                    break;
-                    case EN_BASELINE: // fall through
-                    default:
-                        area.setOffset(context.getBaseline());
-                    break;
-                }
-            break;
-        }
-    }
-
-    public void addAreas(PositionIterator posIter, LayoutContext context) {
-        if (fobj.getLeaderPattern() != EN_USECONTENT) {
-            // use LeafNodeLayoutManager.addAreas()
-            super.addAreas(posIter, context);
-        } else {
-            addId();
-
-            widthAdjustArea(curArea, context);
-
-            // add content areas
-            KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size());
-            clm.addAreas(contentIter, context);
-            offsetArea(curArea, context);
-
-            parentLM.addChildArea(curArea);
-
-            while (posIter.hasNext()) {
-                posIter.next();
-            }
-        }
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        MinOptMax ipd;
-        curArea = get(context);
-        LinkedList returnList = new LinkedList();
-
-        if (curArea == null) {
-            setFinished(true);
-            return null;
-        }
-
-        ipd = getAllocationIPD(context.getRefIPD());
-
-        int bpd = curArea.getBPD();
-        int lead = 0;
-        int total = 0;
-        int middle = 0;
-        switch (verticalAlignment) {
-            case EN_MIDDLE  : middle = bpd / 2 ;
-                                         break;
-            case EN_TOP     : // fall through
-            case EN_BOTTOM  : total = bpd;
-                                         break;
-            case EN_BASELINE: // fall through
-            default:                     lead = bpd;
-                                         break;
-        }
-
-        // create the AreaInfo object to store the computed values
-        areaInfo = new AreaInfo((short) 0, ipd, false,
-                                lead, total, middle);
-
-        // node is a fo:Leader
-        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
-                                    areaInfo.middle,
-                                    new LeafPosition(this, -1), true));
-        returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                        new LeafPosition(this, -1), true));
-        returnList.add
-            (new KnuthGlue(areaInfo.ipdArea.opt,
-                           areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
-                           areaInfo.ipdArea.opt - areaInfo.ipdArea.min, 
-                           new LeafPosition(this, 0), false));
-        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
-                                    areaInfo.middle,
-                                    new LeafPosition(this, -1), true));
-
-        setFinished(true);
-        return returnList;
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        // use the AbstractLayoutManager.hyphenate() null implementation
-        super.hyphenate(pos, hc);
-    }
-
-    public boolean applyChanges(List oldList) {
-        setFinished(false);
-        return false;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              int flaggedPenalty,
-                                              int alignment) {
-        if (isFinished()) {
-            return null;
-        }
-
-        LinkedList returnList = new LinkedList();
-
-        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
-                                    areaInfo.middle,
-                                    new LeafPosition(this, -1), true));
-        returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                        new LeafPosition(this, -1), true));
-        returnList.add
-            (new KnuthGlue(areaInfo.ipdArea.opt,
-                           areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
-                           areaInfo.ipdArea.opt - areaInfo.ipdArea.min, 
-                           new LeafPosition(this, 0), false));
-        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
-                                    areaInfo.middle,
-                                    new LeafPosition(this, -1), true));
-
-        setFinished(true);
-        return returnList;
-    }
-
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java b/src/java/org/apache/fop/layoutmgr/LeafNodeLayoutManager.java
deleted file mode 100644 (file)
index e0fc04d..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.area.Area;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.fo.FObj;
-import org.apache.fop.traits.MinOptMax;
-
-import java.util.List;
-import java.util.LinkedList;
-
-/**
- * Base LayoutManager for leaf-node FObj, ie: ones which have no children.
- * These are all inline objects. Most of them cannot be split (Text is
- * an exception to this rule.)
- * This class can be extended to handle the creation and adding of the
- * inline area.
- */
-public abstract class LeafNodeLayoutManager extends AbstractLayoutManager 
-                                   implements InlineLevelLayoutManager {
-    /**
-     * The inline area that this leafnode will add.
-     */
-    protected InlineArea curArea = null;
-    protected int verticalAlignment;
-    private int lead;
-    private MinOptMax ipd;
-
-    protected boolean bSomethingChanged = false;
-    protected AreaInfo areaInfo = null;
-
-    /**
-     * Store information about the inline area
-     */
-    protected class AreaInfo {
-        protected short iLScount;
-        protected MinOptMax ipdArea;
-        protected boolean bHyphenated;
-        protected int lead;
-        protected int total;
-        protected int middle;
-
-        public AreaInfo(short iLS, MinOptMax ipd, boolean bHyph,
-                        int l, int t, int m) {
-            iLScount = iLS;
-            ipdArea = ipd;
-            bHyphenated = bHyph;
-            lead = l;
-            total = t;
-            middle = m;
-        }
-    }
-
-
-    /**
-     * Create a Leaf node layout mananger.
-     * @param node the FObj to attach to this LM.
-     */
-    public LeafNodeLayoutManager(FObj node) {
-        super(node);
-    }
-
-    /**
-     * Create a Leaf node layout mananger.
-     */
-    public LeafNodeLayoutManager() {
-    }
-
-    /**
-     * get the inline area.
-     * @param context the context used to create the area
-     * @return the current inline area for this layout manager
-     */
-    public InlineArea get(LayoutContext context) {
-        return curArea;
-    }
-
-    /**
-     * Check if this inline area is resolved due to changes in
-     * page or ipd.
-     * Currently not used.
-     * @return true if the area is resolved when adding
-     */
-    public boolean resolved() {
-        return false;
-    }
-
-    /**
-     * Set the current inline area.
-     * @param ia the inline area to set for this layout manager
-     */
-    public void setCurrentArea(InlineArea ia) {
-        curArea = ia;
-    }
-
-    /**
-     * Set the alignment of the inline area.
-     * @param al the vertical alignment positioning
-     */
-    public void setAlignment(int al) {
-        verticalAlignment = al;
-    }
-
-    /**
-     * Set the lead for this inline area.
-     * The lead is the distance from the top of the object
-     * to the baseline.
-     * @param l the lead value
-     */
-    public void setLead(int l) {
-        lead = l;
-    }
-    
-    /** @return the lead value (distance from the top of the object to the baseline) */
-    public int getLead() {
-        return this.lead;
-    }
-
-    /**
-     * This is a leaf-node, so this method is never called.
-     * @param childArea the childArea to add
-     */
-    public void addChildArea(Area childArea) {
-    }
-
-    /**
-     * This is a leaf-node, so this method is never called.
-     * @param childArea the childArea to get the parent for
-     * @return the parent area
-     */
-    public Area getParentArea(Area childArea) {
-        return null;
-    }
-
-    /**
-     * Get the allocation ipd of the inline area.
-     * This method may be overridden to handle percentage values.
-     * @param refIPD the ipd of the parent reference area
-     * @return the min/opt/max ipd of the inline area
-     */
-    protected MinOptMax getAllocationIPD(int refIPD) {
-        return new MinOptMax(curArea.getIPD());
-    }
-
-    /**
-     * Add the area for this layout manager.
-     * This adds the single inline area to the parent.
-     * @param posIter the position iterator
-     * @param context the layout context for adding the area
-     */
-    public void addAreas(PositionIterator posIter, LayoutContext context) {
-        addId();
-
-        InlineArea area = getEffectiveArea();
-        if (area.getAllocIPD() > 0 || area.getAllocBPD() > 0) {
-            offsetArea(area, context);
-            widthAdjustArea(area, context);
-            parentLM.addChildArea(area);
-        }
-
-        while (posIter.hasNext()) {
-            posIter.next();
-        }
-    }
-
-    /**
-     * @return the effective area to be added to the area tree. Normally, this is simply "curArea"
-     * but in the case of page-number(-citation) curArea is cloned, updated and returned.
-     */
-    protected InlineArea getEffectiveArea() {
-        return curArea;
-    }
-    
-    protected void addId() {
-        // Do nothing here, overriden in subclasses that have an 'id' property.
-    }
-    
-    /**
-     * Offset this area.
-     * Offset the inline area in the bpd direction when adding the
-     * inline area.
-     * This is used for vertical alignment.
-     * Subclasses should override this if necessary.
-     * @param area the inline area to be updated
-     * @param context the layout context used for adding the area
-     */
-    protected void offsetArea(InlineArea area, LayoutContext context) {
-        int bpd = area.getBPD();
-        switch (verticalAlignment) {
-            case EN_MIDDLE:
-                area.setOffset(context.getMiddleBaseline() - bpd / 2);
-            break;
-            case EN_TOP:
-                area.setOffset(context.getTopBaseline());
-            break;
-            case EN_BOTTOM:
-                area.setOffset(context.getBottomBaseline() - bpd);
-            break;
-            case EN_BASELINE:
-            default:
-                area.setOffset(context.getBaseline() - bpd);
-            break;
-        }
-    }
-
-    /**
-     * Adjust the width of the area when adding.
-     * This uses the min/opt/max values to adjust the with
-     * of the inline area by a percentage.
-     * @param area the inline area to be updated
-     * @param context the layout context for adding this area
-     */
-    protected void widthAdjustArea(InlineArea area, LayoutContext context) {
-        double dAdjust = context.getIPDAdjust();
-        int width = areaInfo.ipdArea.opt;
-        if (dAdjust < 0) {
-            width = (int) (width + dAdjust * (areaInfo.ipdArea.opt
-                                             - areaInfo.ipdArea.min));
-        } else if (dAdjust > 0) {
-            width = (int) (width + dAdjust * (areaInfo.ipdArea.max
-                                             - areaInfo.ipdArea.opt));
-        }
-        area.setIPD(width);
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        MinOptMax ipd;
-        curArea = get(context);
-
-        if (curArea == null) {
-            setFinished(true);
-            return null;
-        }
-        ipd = getAllocationIPD(context.getRefIPD());
-
-        int bpd = curArea.getBPD();
-        int lead = 0;
-        int total = 0;
-        int middle = 0;
-        switch (verticalAlignment) {
-            case EN_MIDDLE  : middle = bpd / 2 ;
-                                         lead = bpd / 2 ;
-                                         break;
-            case EN_TOP     : total = bpd;
-                                         break;
-            case EN_BOTTOM  : total = bpd;
-                                         break;
-            case EN_BASELINE:
-            default:                     
-                //lead = bpd;
-                lead = getLead();
-                total = bpd;
-                break;
-        }
-
-        // create the AreaInfo object to store the computed values
-        areaInfo = new AreaInfo((short) 0, ipd, false,
-                                lead, total, middle);
-
-        // node is a fo:ExternalGraphic, fo:InstreamForeignObject,
-        // fo:PageNumber or fo:PageNumberCitation
-        LinkedList returnList = new LinkedList();
-        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
-                                    areaInfo.total, areaInfo.middle,
-                                    new LeafPosition(this, 0), false));
-        setFinished(true);
-        return returnList;
-    }
-
-    public List addALetterSpaceTo(List oldList) {
-        // return the unchanged elements
-        return oldList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-    }
-
-    public boolean applyChanges(List oldList) {
-        setFinished(false);
-        return false;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              /*int flaggedPenalty,*/
-                                              int alignment) {
-        if (isFinished()) {
-            return null;
-        }
-
-        LinkedList returnList = new LinkedList();
-
-        // fobj is a fo:ExternalGraphic, fo:InstreamForeignObject,
-        // fo:PageNumber or fo:PageNumberCitation
-        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
-                                          areaInfo.total, areaInfo.middle,
-                                          new LeafPosition(this, 0), true));
-
-        setFinished(true);
-        return returnList;
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
deleted file mode 100644 (file)
index 3f54fb4..0000000
+++ /dev/null
@@ -1,1500 +0,0 @@
-/*
- * Copyright 1999-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: LineLayoutManager.java,v 1.17 2004/04/02 10:38:29 cbowditch Exp $ */
-
-package org.apache.fop.layoutmgr;
-
-import org.apache.fop.datatypes.Length;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.flow.Block;
-import org.apache.fop.fo.properties.CommonHyphenation;
-import org.apache.fop.hyphenation.Hyphenation;
-import org.apache.fop.hyphenation.Hyphenator;
-import org.apache.fop.area.LineArea;
-
-import java.util.ListIterator;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.LinkedList;
-
-import org.apache.fop.traits.MinOptMax;
-
-/**
- * LayoutManager for lines. It builds one or more lines containing
- * inline areas generated by its sub layout managers.
- * A break is found for each line which may contain one of more
- * breaks from the child layout managers.
- * Once a break is found then it is return for the parent layout
- * manager to handle.
- * When the areas are being added to the page this manager
- * creates a line area to contain the inline areas added by the
- * child layout managers.
- */
-public class LineLayoutManager extends InlineStackingLayoutManager 
-                               implements BlockLevelLayoutManager {
-
-    private Block fobj; 
-    
-    private void initialize() {
-        bTextAlignment = fobj.getTextAlign();
-        bTextAlignmentLast = fobj.getTextAlignLast();
-        textIndent = fobj.getTextIndent();
-        hyphProps = fobj.getCommonHyphenation();
-        
-        //
-        if (bTextAlignment != EN_JUSTIFY && bTextAlignmentLast == EN_JUSTIFY) {
-            effectiveAlignment = 0;
-        } else {
-            effectiveAlignment = bTextAlignment;
-        }
-    }
-
-    /**
-     * Private class to store information about inline breaks.
-     * Each value holds the start and end indexes into a List of
-     * inline break positions.
-     */
-    private static class LineBreakPosition extends LeafPosition {
-        // int iPos;
-        int iParIndex; // index of the Paragraph this Position refers to
-        int availableShrink;
-        int availableStretch;
-        int difference;
-        double dAdjust; // Percentage to adjust (stretch or shrink)
-        double ipdAdjust; // Percentage to adjust (stretch or shrink)
-        int startIndent;
-        int lineHeight;
-        int lineWidth;
-        int baseline;
-        int topShift;
-        int bottomShift;
-
-        LineBreakPosition(LayoutManager lm, int index, int iBreakIndex,
-                          int shrink, int stretch, int diff,
-                          double ipdA, double adjust, int ind,
-                          int lh, int lw, int bl, int ts, int bs) {
-            super(lm, iBreakIndex);
-            availableShrink = shrink;
-            availableStretch = stretch;
-            difference = diff;
-            iParIndex = index;
-            ipdAdjust = ipdA;
-            dAdjust = adjust;
-            startIndent = ind;
-            lineHeight = lh;
-            lineWidth = lw;
-            baseline = bl;
-            topShift = ts;
-            bottomShift = bs;
-        }
-        
-    }
-
-
-    /** Break positions returned by inline content. */
-    private List vecInlineBreaks = new java.util.ArrayList();
-
-    private int bTextAlignment = EN_JUSTIFY;
-    private int bTextAlignmentLast;
-    private int effectiveAlignment;
-    private Length textIndent;
-    private int iIndents = 0;
-    private CommonHyphenation hyphProps;
-    //private LayoutProps layoutProps;
-
-    private int lineHeight;
-    private int lead;
-    private int follow;
-    // offset of the middle baseline with respect to the main baseline
-    private int middleShift;
-
-    private List knuthParagraphs = null;
-    private int iReturnedLBP = 0;
-    private int iStartElement = 0;
-    private int iEndElement = 0;
-
-    //     parameters of Knuth's algorithm:
-    // penalty value for flagged penalties
-    private int flaggedPenalty = 50;
-
-    private LineLayoutPossibilities lineLayouts;
-    private List lineLayoutsList;
-    private int iLineWidth = 0;
-
-    // this constant is used to create elements when text-align is center:
-    // every TextLM descendant of LineLM must use the same value, 
-    // otherwise the line breaking algorithm does not find the right
-    // break point
-    public static final int DEFAULT_SPACE_WIDTH = 3336;
-
-
-    // this class is used to remember
-    // which was the first element in the paragraph
-    // returned by each LM
-    private class Update {
-        private InlineLevelLayoutManager inlineLM;
-        private int iFirstIndex;
-
-        public Update(InlineLevelLayoutManager lm, int index) {
-            inlineLM = lm;
-            iFirstIndex = index;
-        }
-    }
-
-    // this class represents a paragraph
-    private class Paragraph extends KnuthSequence {
-        // space at the end of the last line (in millipoints)
-        private MinOptMax lineFiller;
-        private int textAlignment;
-        private int textAlignmentLast;
-        private int textIndent;
-        private int lineWidth;
-        // the LM which created the paragraph
-        private LineLayoutManager layoutManager;
-
-        public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
-                         int indent) {
-            super();
-            layoutManager = llm;
-            textAlignment = alignment;
-            textAlignmentLast = alignmentLast;
-            textIndent = indent;
-        }
-
-        public void startParagraph(int lw) {
-            lineWidth = lw;
-            startSequence();
-        }
-
-        public void startSequence() {
-            // set the minimum amount of empty space at the end of the
-            // last line
-            if (bTextAlignment == EN_CENTER) {
-                lineFiller = new MinOptMax(0); 
-            } else {
-                lineFiller = new MinOptMax(0, (int)(lineWidth / 12), lineWidth); 
-            }
-
-            // add auxiliary elements at the beginning of the paragraph
-            if (bTextAlignment == EN_CENTER && bTextAlignmentLast != EN_JUSTIFY) {
-                this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
-                                       null, false));
-                ignoreAtStart ++;
-            }
-
-            // add the element representing text indentation
-            // at the beginning of the first paragraph
-            if (knuthParagraphs.size() == 0
-                        && fobj.getTextIndent().getValue() != 0) {
-                this.add(new KnuthInlineBox(fobj.getTextIndent().getValue(), 0, 0, 0,
-                                      null, false));
-                ignoreAtStart ++;
-            }
-        }
-
-        public void endParagraph() {
-            KnuthSequence finishedPar = this.endSequence();
-            if (finishedPar != null) {
-                knuthParagraphs.add(finishedPar);
-            }
-        }
-
-        public KnuthSequence endSequence() {
-            // remove glue and penalty item at the end of the paragraph
-            while (this.size() > ignoreAtStart
-                   && !((KnuthElement)this.get(this.size() - 1)).isBox()) {
-                this.remove(this.size() - 1);
-            }
-            if (this.size() > ignoreAtStart) {
-                if (bTextAlignment == EN_CENTER
-                    && bTextAlignmentLast != EN_JUSTIFY) {
-                    this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
-                                           null, false));
-                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
-                                              false, null, false));
-                    ignoreAtEnd = 2;
-                } else if (bTextAlignmentLast != EN_JUSTIFY) {
-                    // add the elements representing the space
-                    // at the end of the last line
-                    // and the forced break
-                    this.add(new KnuthPenalty(0, KnuthElement.INFINITE, 
-                                              false, null, false));
-                    this.add(new KnuthGlue(lineFiller.opt, 
-                            lineFiller.max - lineFiller.opt, 
-                            lineFiller.opt - lineFiller.min, null, false));
-                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
-                                              false, null, false));
-                    ignoreAtEnd = 3;
-                } else {
-                    // add only the element representing the forced break
-                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
-                                              false, null, false));
-                    ignoreAtEnd = 1;
-                }
-                return this;
-            } else {
-                this.clear();
-                return null;
-            }
-        }
-
-    }
-
-    private class LineBreakingAlgorithm extends BreakingAlgorithm {
-        private LineLayoutManager thisLLM;
-        private int pageAlignment;
-        private int activePossibility;
-        private int addedPositions;
-        private int textIndent;
-        private int fillerMinWidth;
-        private int lineHeight;
-        private int lead;
-        private int follow;
-        private int middleshift;
-        private int maxDiff;
-        private static final double MAX_DEMERITS = 10e6;
-
-        public LineBreakingAlgorithm (int pageAlign,
-                                      int textAlign, int textAlignLast,
-                                      int indent, int fillerWidth,
-                                      int lh, int ld, int fl, int ms, boolean first,
-                                      LineLayoutManager llm) {
-            super(textAlign, textAlignLast, first, false);
-            pageAlignment = pageAlign;
-            textIndent = indent;
-            fillerMinWidth = fillerWidth;
-            lineHeight = lh;
-            lead = ld;
-            follow = fl;
-            middleshift = ms;
-            thisLLM = llm;
-            activePossibility = -1;
-            maxDiff = fobj.getWidows() >= fobj.getOrphans() 
-                    ? fobj.getWidows()
-                    : fobj.getOrphans();
-        }
-
-        public void updateData1(int lineCount, double demerits) {
-            lineLayouts.addPossibility(lineCount, demerits);
-            log.trace("Layout possibility in " + lineCount + " lines; break at position:");
-        }
-
-        public void updateData2(KnuthNode bestActiveNode,
-                                KnuthSequence par,
-                                int total) {
-            // compute indent and adjustment ratio, according to
-            // the value of text-align and text-align-last
-            int indent = 0;
-            int difference = (bestActiveNode.line < total) ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth;
-            int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
-            indent += (textAlign == Constants.EN_CENTER) ?
-                          difference / 2 :
-                          (textAlign == Constants.EN_END) ? difference : 0;
-            indent += (bestActiveNode.line == 1 && bFirst) ? 
-                          textIndent : 0;
-            double ratio = (textAlign == Constants.EN_JUSTIFY
-                            || bestActiveNode.adjustRatio < 0) ? bestActiveNode.adjustRatio : 0;
-
-            // add nodes at the beginning of the list, as they are found
-            // backwards, from the last one to the first one
-
-            // the first time this method is called, initialize activePossibility
-            if (activePossibility == -1) {
-                activePossibility = 0;
-                addedPositions = 0;
-            }
-
-            if (addedPositions == lineLayouts.getLineCount(activePossibility)) {
-                activePossibility ++;
-                addedPositions = 0;
-                //System.out.println(" ");
-            }
-
-            //System.out.println("LLM> (" + (lineLayouts.getLineNumber(activePossibility) - addedPositions) + ") difference = " + difference + " ratio = " + ratio);
-            lineLayouts.addBreakPosition(makeLineBreakPosition(par,
-                                                               (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1: 0),
-                                                               bestActiveNode.position,
-                                                               bestActiveNode.availableShrink - (addedPositions > 0 ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min), bestActiveNode.availableStretch, difference, ratio, indent),
-                                         activePossibility);
-            addedPositions ++;
-        }
-
-        /* reset activePossibility, as if breakpoints have not yet been computed
-         */
-        public void resetAlgorithm() {
-            activePossibility = -1;
-        }
-
-        private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
-                                                        int firstElementIndex,
-                                                        int lastElementIndex,
-                                                        int availableShrink, int availableStretch, int difference,
-                                                        double ratio,
-                                                        int indent) {
-            // line height calculation
-
-            int halfLeading = (lineHeight - lead - follow) / 2;
-            // height before the main baseline
-            int lineLead = lead;
-            // maximum size of top and bottom alignment
-            int maxtb = follow;
-            // max size of middle alignment before and after the middle baseline
-            int middlefollow = maxtb;
-            // true if this line contains only zero-height, auxiliary boxes
-            // and the actual line width is 0; in this case, the line "collapses"
-            // i.e. the line area will have bpd = 0
-            boolean bZeroHeightLine = (difference == iLineWidth);
-
-            // if line-stacking-strategy is "font-height", the line height
-            // is not affected by its content
-            if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) {
-                ListIterator inlineIterator
-                    = par.listIterator(firstElementIndex);
-                for (int j = firstElementIndex;
-                     j <= lastElementIndex;
-                     j++) {
-                    KnuthElement element = (KnuthElement) inlineIterator.next();
-                    if (element.isBox()) {
-                        if (((KnuthInlineBox) element).getLead() > lineLead) {
-                            lineLead = ((KnuthInlineBox) element).getLead();
-                        }
-                        if (((KnuthInlineBox) element).getTotal() > maxtb) {
-                            maxtb = ((KnuthInlineBox) element).getTotal();
-                        }
-                        if (((KnuthInlineBox) element).getMiddle() > lineLead + middleShift) {
-                            lineLead += ((KnuthInlineBox) element).getMiddle()
-                                        - lineLead - middleShift;
-                        }
-                        if (((KnuthInlineBox) element).getMiddle() > middlefollow - middleShift) {
-                            middlefollow += ((KnuthInlineBox) element).getMiddle()
-                                            - middlefollow + middleShift;
-                        }
-                        if (bZeroHeightLine
-                            && (!element.isAuxiliary()
-                                || ((KnuthInlineBox) element).getTotal() > 0
-                                || ((KnuthInlineBox) element).getLead() > 0
-                                || ((KnuthInlineBox) element).getMiddle() > 0)) {
-                            bZeroHeightLine = false;
-                        }
-                    }
-                }
-
-                if (maxtb - lineLead > middlefollow) {
-                    middlefollow = maxtb - lineLead;
-                }
-            }
-
-            constantLineHeight = lineLead + middlefollow + (lineHeight - lead - follow);
-
-            if (bZeroHeightLine) {
-                return new LineBreakPosition(thisLLM,
-                                             knuthParagraphs.indexOf(par),
-                                             lastElementIndex,
-                                             availableShrink, availableStretch, difference, ratio, 0, indent,
-                                             0, iLineWidth,
-                                             0, 0, 0);
-            } else {
-                return new LineBreakPosition(thisLLM,
-                                             knuthParagraphs.indexOf(par),
-                                             lastElementIndex,
-                                             availableShrink, availableStretch, difference, ratio, 0, indent,
-                                             lineLead + middlefollow + (lineHeight - lead - follow), iLineWidth,
-                                             lineLead + halfLeading,
-                                             - lineLead, middlefollow);
-            }
-        }
-
-        public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
-                                      double threshold, boolean force,
-                                      boolean hyphenationAllowed) {
-            return super.findBreakingPoints(par, /*lineWidth,*/ 
-                    threshold, force, hyphenationAllowed);
-        }
-
-        protected int filterActiveNodes() {
-            KnuthNode bestActiveNode = null;
-
-            if (pageAlignment == EN_JUSTIFY) {
-                // leave all active nodes and find the optimum line number
-                //System.out.println("LBA.filterActiveNodes> " + activeNodeCount + " layouts");
-                for (int i = startLine; i < endLine; i++) {
-                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
-                        //System.out.println("                       + lines = " + node.line + " demerits = " + node.totalDemerits);
-                        bestActiveNode = compareNodes(bestActiveNode, node);
-                    }
-                }
-
-                // scan the node set once again and remove some nodes
-                //System.out.println("LBA.filterActiveList> layout selection");
-                for (int i = startLine; i < endLine; i++) {
-                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
-                        //if (Math.abs(node.line - bestActiveNode.line) > maxDiff) {
-                        //if (false) {
-                        if (node.line != bestActiveNode.line
-                            && node.totalDemerits > MAX_DEMERITS) {
-                            //System.out.println("                     XXX lines = " + node.line + " demerits = " + node.totalDemerits);
-                            removeNode(i, node);
-                        } else {
-                            //System.out.println("                      ok lines = " + node.line + " demerits = " + node.totalDemerits);
-                        }
-                    }
-                }
-            } else {
-                // leave only the active node with fewest total demerits
-                for (int i = startLine; i < endLine; i++) {
-                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
-                        bestActiveNode = compareNodes(bestActiveNode, node);
-                        if (node != bestActiveNode) {
-                            removeNode(i, node);
-                        }
-                    }
-                }
-            }
-            return bestActiveNode.line;
-        }
-    }
-
-      
-    private int constantLineHeight = 12000;
-      
-
-    /**
-     * Create a new Line Layout Manager.
-     * This is used by the block layout manager to create
-     * line managers for handling inline areas flowing into line areas.
-     *
-     * @param lh the default line height
-     * @param l the default lead, from top to baseline
-     * @param f the default follow, from baseline to bottom
-     */
-    public LineLayoutManager(Block block, int lh, int l, int f, int ms) {
-        super(block);
-        fobj = block;
-        // the child FObj are owned by the parent BlockLM
-        // this LM has all its childLMs preloaded
-        fobjIter = null;
-        lineHeight = lh;
-        lead = l;
-        follow = f;
-        middleShift = ms;
-        initialize(); // Normally done when started by parent!
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
-        // Get a break from currently active child LM
-        // Set up constraints for inline level managers
-        InlineLevelLayoutManager curLM ; // currently active LM
-
-        // IPD remaining in line
-        MinOptMax availIPD = context.getStackLimit();
-
-        clearPrevIPD();
-        int iPrevLineEnd = vecInlineBreaks.size();
-
-        if (iPrevLineEnd == 0 && bTextAlignment == EN_START) {
-            availIPD.subtract(new MinOptMax(textIndent.getValue()));
-        }
-
-        //PHASE 1: Create Knuth elements
-        if (knuthParagraphs == null) {
-            // it's the first time this method is called
-            knuthParagraphs = new ArrayList();
-
-            // here starts Knuth's algorithm
-            //TODO availIPD should not really be used here, so we can later support custom line
-            //widths for for each line (side-floats, differing available IPD after page break)
-            collectInlineKnuthElements(context, availIPD);
-        } else {
-            // this method has been called before
-            // all line breaks are already calculated
-        }
-
-        // return finished when there's no content
-        if (knuthParagraphs.size() == 0) {
-            setFinished(true);
-            return null;
-        }
-
-        //PHASE 2: Create line breaks
-        return findOptimalLineBreakingPoints(alignment);
-        /*
-        LineBreakPosition lbp = null;
-        if (breakpoints == null) {
-            // find the optimal line breaking points for each paragraph
-            breakpoints = new ArrayList();
-            ListIterator paragraphsIterator
-                = knuthParagraphs.listIterator(knuthParagraphs.size());
-            Paragraph currPar = null;
-            while (paragraphsIterator.hasPrevious()) {
-                currPar = (Paragraph) paragraphsIterator.previous();
-                findBreakingPoints(currPar, context.getStackLimit().opt);
-            }
-        }*/
-
-        //PHASE 3: Return lines
-
-        /*
-        // get a break point from the list
-        lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
-        if (iReturnedLBP == breakpoints.size()) {
-            setFinished(true);
-        }
-
-        BreakPoss curLineBP = new BreakPoss(lbp);
-        curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
-        curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
-        return curLineBP;
-        */
-    }
-
-    /**
-     * Phase 1 of Knuth algorithm: Collect all inline Knuth elements before determining line breaks.
-     * @param context the LayoutContext
-     * @param availIPD available IPD for line (should be removed!) 
-     */
-    private void collectInlineKnuthElements(LayoutContext context, MinOptMax availIPD) {
-        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);
-        while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
-            if ((returnedList
-                 = curLM.getNextKnuthElements(inlineLC,
-                                              effectiveAlignment))
-                != null) {
-                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);
-                    } 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());
-                    }
-                    // 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());
-                    }
-                }
-
-                // 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();
-                    }
-                }
-
-                // 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));
-                    }
-                    knuthPar.endParagraph();
-                    knuthPar = new Paragraph(this, 
-                                             bTextAlignment, bTextAlignmentLast, 
-                                             textIndent.getValue());
-                    knuthPar.startParagraph(availIPD.opt);
-                    bPrevWasKnuthBox = false;
-                }
-            } else {
-                // curLM returned null; this can happen
-                // if it has nothing more to layout,
-                // so just iterate once more to see
-                // if there are other children
-            }
-        }
-        knuthPar.endParagraph();
-        ElementListObserver.observe(knuthPar, "line", null);
-    }
-
-    /**
-     * Find a set of breaking points.
-     * This method is called only once by getNextBreakPoss, and it 
-     * subsequently calls the other findBreakingPoints() method with 
-     * different parameters, until a set of breaking points is found.
-     *
-     * @param par       the list of elements that must be parted
-     *                  into lines
-     * @param lineWidth the desired length ot the lines
-     */
-    /*
-    private void findBreakingPoints(Paragraph par, int lineWidth) {
-        // maximum adjustment ratio permitted
-        float maxAdjustment = 1;
-
-        // first try
-        if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
-            // the first try failed, now try something different
-            log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
-            if (hyphProps.hyphenate == Constants.EN_TRUE) {
-                // consider every hyphenation point as a legal break
-                findHyphenationPoints(par);
-            } else {
-                // try with a higher threshold
-                maxAdjustment = 5;
-            }
-
-            if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
-                // the second try failed too, try with a huge threshold;
-                // if this fails too, use a different algorithm
-                log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
-                          + (hyphProps.hyphenate == Constants.EN_TRUE ? " and hyphenation" : ""));
-                maxAdjustment = 20;
-                if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) {
-                    log.debug("No set of breaking points found, using first-fit algorithm");
-                }
-            }
-        }
-    }
-    
-    private boolean findBreakingPoints(Paragraph par, int lineWidth,
-            double threshold, boolean force) {
-        KnuthParagraph knuthPara = new KnuthParagraph(par);
-        int lines = knuthPara.findBreakPoints(lineWidth, threshold, force);
-        if (lines == 0) {
-            return false;
-        }
-        
-        for (int i = lines-1; i >= 0; i--) {
-            int line = i+1;
-            if (log.isTraceEnabled()) {
-                log.trace("Making line from " + knuthPara.getStart(i) + " to " + 
-                           knuthPara.getEnd(i));
-            }
-            // compute indent and adjustment ratio, according to
-            // the value of text-align and text-align-last
-
-            int difference = knuthPara.getDifference(i);
-            if (line == lines) {
-                difference += par.lineFillerWidth;
-            }    
-            int textAlign = (line < lines)
-                ? bTextAlignment : bTextAlignmentLast;
-            int indent = (textAlign == EN_CENTER)
-                ? difference / 2
-                : (textAlign == EN_END) ? difference : 0;
-            indent += (line == 1 && knuthParagraphs.indexOf(par) == 0)
-                ? textIndent.getValue() : 0;
-            double ratio = (textAlign == EN_JUSTIFY)
-                ? knuthPara.getAdjustRatio(i) : 0;
-
-            int start = knuthPara.getStart(i);
-            int end = knuthPara.getEnd(i);
-            makeLineBreakPosition(par, start, end, 0, ratio, indent);
-        }
-        return true;        
-    }
-
-    private void makeLineBreakPosition(Paragraph par,
-                                       int firstElementIndex, int lastElementIndex,
-                                       int insertIndex, double ratio, int indent) {
-        // line height calculation
-
-        int halfLeading = (lineHeight - lead - follow) / 2;
-        // height above the main baseline
-        int lineLead = lead + halfLeading;
-        // maximum size of top and bottom alignment
-        int maxtb = follow + halfLeading;
-        // max size of middle alignment above and below the middle baseline
-        int middlefollow = maxtb;
-
-        ListIterator inlineIterator
-            = par.listIterator(firstElementIndex);
-        for (int j = firstElementIndex;
-             j <= lastElementIndex;
-             j++) {
-            KnuthElement element = (KnuthElement) inlineIterator.next();
-            if (element.isBox()) {
-                KnuthInlineBox box = (KnuthInlineBox)element;
-                if (box.getLead() > lineLead) {
-                    lineLead = box.getLead();
-                }
-                if (box.getTotal() > maxtb) {
-                    maxtb = box.getTotal();
-                }
-                if (box.getMiddle() > lineLead + middleShift) {
-                    lineLead += box.getMiddle()
-                                - lineLead - middleShift;
-                }
-                if (box.getMiddle() > middlefollow - middleShift) {
-                    middlefollow += box.getMiddle()
-                                    - middlefollow + middleShift;
-                }
-            }
-        }
-
-        if (maxtb - lineLead > middlefollow) {
-                    middlefollow = maxtb - lineLead;
-        }
-
-        breakpoints.add(insertIndex,
-                        new LineBreakPosition(this,
-                                              knuthParagraphs.indexOf(par),
-                                              lastElementIndex ,
-                                              ratio, 0, indent,
-                                              lineLead + middlefollow,
-                                              lineLead));
-    }*/
-
-    
-    /**
-     * Phase 2 of Knuth algorithm: find optimal break points.
-     * @param alignment alignmenr of the paragraph
-     * @return a list of Knuth elements representing broken lines
-     */
-    private LinkedList findOptimalLineBreakingPoints(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());
-                }
-            }
-            lineLayoutsList.add(0, lineLayouts);
-        }
-        
-        
-        setFinished(true);
-    
-        //Post-process the line breaks found
-        return postProcessLineBreaks(alignment);
-    }
-
-    private LinkedList postProcessLineBreaks(int alignment) {
-    
-        LinkedList returnList = new LinkedList();
-        
-        for (int p = 0; p < knuthParagraphs.size(); p ++) {
-            // null penalty between paragraphs
-            if (p > 0
-                && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
-                returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
-            }
-        
-            lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
-        
-            if (alignment == EN_JUSTIFY) {
-                /* justified vertical alignment (not in the XSL FO recommendation):
-                   create a multi-layout sequence whose elements will contain 
-                   a conventional Position */
-                Position returnPosition = new LeafPosition(this, p);
-                createElements(returnList, lineLayouts, returnPosition);
-            } else {
-                /* "normal" vertical alignment: create a sequence whose boxes
-                   represent effective lines, and contain LineBreakPositions */
-                Position returnPosition = new LeafPosition(this, p);
-                int startIndex = 0;
-                for (int i = 0;
-                        i < lineLayouts.getChosenLineCount();
-                        i++) {
-                    if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
-                        && i >= fobj.getOrphans()
-                        && i <= lineLayouts.getChosenLineCount() - fobj.getWidows()
-                        && returnList.size() > 0) {
-                        // null penalty allowing a page break between lines
-                        returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
-                    }
-                    int endIndex = ((LineBreakPosition) lineLayouts.getChosenPosition(i)).getLeafPos();
-                    // 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);
-                    while (elementIterator.nextIndex() <= endIndex) {
-                        KnuthElement element = (KnuthElement) elementIterator.next();
-                        if (element instanceof KnuthInlineBox
-                            && ((KnuthInlineBox) element).isAnchor()) {
-                            footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
-                        }
-                    }
-                    startIndex = endIndex + 1;
-                    returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
-                                                     footnoteList, lineLayouts.getChosenPosition(i), false));
-                }
-            }
-        }
-        
-        return returnList;
-    }
-
-
-    private void createElements(List list, LineLayoutPossibilities lineLayouts,
-                                Position elementPosition) {
-        /* number of normal, inner lines */
-        int nInnerLines = 0;
-        /* number of lines that can be used in order to fill more space */
-        int nOptionalLines = 0;
-        /* number of lines that can be used in order to fill more space
-           only if the paragraph is not parted */
-        int nConditionalOptionalLines = 0;
-        /* number of lines that can be omitted in order to fill less space */
-        int nEliminableLines = 0;
-        /* number of lines that can be omitted in order to fill less space
-           only if the paragraph is not parted */
-        int nConditionalEliminableLines = 0;
-        /* number of the first unbreakable lines */
-        int nFirstLines = fobj.getOrphans();
-        /* number of the last unbreakable lines */
-        int nLastLines = fobj.getWidows();
-        /* sub-sequence used to separate the elements representing different lines */
-        List breaker = new LinkedList();
-
-        /* comment out the next lines in order to test particular situations */
-        if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMinLineCount()) {
-            nInnerLines = lineLayouts.getMinLineCount() - (fobj.getOrphans() + fobj.getWidows());
-            nOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
-            nEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
-        } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getOptLineCount()) {
-            nOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
-            nEliminableLines = lineLayouts.getOptLineCount() - (fobj.getOrphans() + fobj.getWidows());
-            nConditionalEliminableLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getMinLineCount();
-        } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMaxLineCount()) {
-            nOptionalLines = lineLayouts.getMaxLineCount() - (fobj.getOrphans() + fobj.getWidows());
-            nConditionalOptionalLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getOptLineCount();
-            nConditionalEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
-            nFirstLines -= nConditionalOptionalLines;
-        } else {
-            nConditionalOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
-            nConditionalEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
-            nFirstLines = lineLayouts.getOptLineCount();
-            nLastLines = 0;
-        }
-        /* comment out the previous lines in order to test particular situations */
-
-        /* use these lines to test particular situations
-        nInnerLines = 0;
-        nOptionalLines = 1;
-        nConditionalOptionalLines = 2;
-        nEliminableLines = 0;
-        nConditionalEliminableLines = 0;
-        nFirstLines = 1;
-        nLastLines = 3;
-        */
-
-        if (nLastLines != 0
-            && (nConditionalOptionalLines > 0 || nConditionalEliminableLines > 0)) {
-            breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
-            breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight,
-                                        -nConditionalEliminableLines * constantLineHeight,
-                                        LINE_NUMBER_ADJUSTMENT, elementPosition, false));
-            breaker.add(new KnuthPenalty(nConditionalOptionalLines * constantLineHeight,
-                                           0, false, elementPosition, false));
-            breaker.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
-                                        nConditionalEliminableLines * constantLineHeight,
-                                        LINE_NUMBER_ADJUSTMENT, elementPosition, false));
-        } else if (nLastLines != 0) {
-            breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false));
-        }
-
-        //System.out.println("first=" + nFirstLines + " inner=" + nInnerLines
-        //                   + " optional=" + nOptionalLines + " eliminable=" + nEliminableLines
-        //                   + " last=" + nLastLines
-        //                   + " (condOpt=" + nConditionalOptionalLines + " condEl=" + nConditionalEliminableLines + ")");
-
-        // creation of the elements:
-        // first group of lines
-        list.add(new KnuthBox(nFirstLines * constantLineHeight, elementPosition,
-                              (nLastLines == 0
-                               && nConditionalOptionalLines == 0
-                               && nConditionalEliminableLines == 0 ? true : false)));
-        if (nConditionalOptionalLines > 0
-            || nConditionalEliminableLines > 0) {
-            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
-            list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
-                                   nConditionalEliminableLines * constantLineHeight,
-                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
-            list.add(new KnuthBox(0, elementPosition,
-                                  (nLastLines == 0 ? true : false)));
-        }
-
-        // optional lines
-        for (int i = 0; i < nOptionalLines; i++) {
-            list.addAll(breaker);
-            list.add(new KnuthBox(0, elementPosition, false));
-            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
-            list.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
-                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
-            list.add(new KnuthBox(0, elementPosition, false));
-        }
-
-        // eliminable lines
-        for (int i = 0; i < nEliminableLines; i++) {
-            list.addAll(breaker);
-            list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
-            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
-            list.add(new KnuthGlue(0, 0, 1 * constantLineHeight,
-                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
-            list.add(new KnuthBox(0, elementPosition, false));
-        }
-
-        // inner lines
-        for (int i = 0; i < nInnerLines; i++) {
-            list.addAll(breaker);
-            list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
-        }
-
-        // last group of lines
-        if (nLastLines > 0) {
-            list.addAll(breaker);
-            list.add(new KnuthBox(nLastLines * constantLineHeight,
-                                  elementPosition, true));
-        }
-    }
-
-    public boolean mustKeepTogether() {
-        return false;
-    }
-
-    public boolean mustKeepWithPrevious() {
-        return false;
-    }
-
-    public boolean mustKeepWithNext() {
-        return false;
-    }
-
-    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
-        LeafPosition pos = (LeafPosition)lastElement.getPosition();
-        int totalAdj = adj;
-        //if (lastElement.isPenalty()) {
-        //    totalAdj += lastElement.getW();
-        //}
-        //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight);
-        int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight + (adj > 0 ? - 0.4 : 0.4));
-        //System.out.println("   LLM> variazione calcolata = " + ((double) totalAdj / constantLineHeight) + " variazione applicata = " + lineNumberDifference);
-        lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(pos.getLeafPos());
-        lineNumberDifference = lineLayouts.applyLineCountAdjustment(lineNumberDifference);
-        return lineNumberDifference * constantLineHeight;
-    }
-
-    public void discardSpace(KnuthGlue spaceGlue) {
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList, int alignment) {
-        LinkedList returnList = new LinkedList();
-        for (int p = 0;
-             p < knuthParagraphs.size();
-             p ++) {
-            lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
-            //System.out.println("demerits of the chosen layout: " + lineLayouts.getChosenDemerits());
-            for (int i = 0;
-                 i < lineLayouts.getChosenLineCount();
-                 i ++) {
-                if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
-                    && i >= fobj.getOrphans()
-                    && i <= lineLayouts.getChosenLineCount() - fobj.getWidows()) {
-                    // null penalty allowing a page break between lines
-                    returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
-                }
-                LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
-                //System.out.println("LLM.getChangedKnuthElements> lineWidth= " + lbp.lineWidth + " difference= " + lbp.difference);
-                //System.out.println("                             shrink= " + lbp.availableShrink + " stretch= " + lbp.availableStretch);
-
-                //System.out.println("linewidth= " + lbp.lineWidth + " difference= " + lbp.difference + " indent= " + lbp.startIndent);
-                MinOptMax contentIPD;
-                if (alignment == EN_JUSTIFY) {
-                    contentIPD = new MinOptMax(
-                        lbp.lineWidth - lbp.difference - lbp.availableShrink, 
-                        lbp.lineWidth - lbp.difference, 
-                        lbp.lineWidth - lbp.difference + lbp.availableStretch);
-                } else if (alignment == EN_CENTER) {
-                    contentIPD = new MinOptMax(lbp.lineWidth - 2 * lbp.startIndent);
-                } else if (alignment == EN_END) {
-                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent);
-                } else {
-                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent);
-                }
-                returnList.add(new KnuthBlockBox(lbp.lineHeight,
-                                                 contentIPD,
-                                                 (lbp.ipdAdjust != 0 ? lbp.lineWidth - lbp.difference : 0),
-                                                 lbp, false));
-            }
-        }
-        return returnList;
-    }
-
-    /**
-     * find hyphenation points for every word int the current paragraph
-     * @ param currPar the paragraph whose words will be hyphenated
-     */
-    private void findHyphenationPoints(Paragraph currPar){
-        // hyphenate every word
-        ListIterator currParIterator
-            = currPar.listIterator(currPar.ignoreAtStart);
-        // list of TLM involved in hyphenation
-        LinkedList updateList = new LinkedList();
-        KnuthElement firstElement = null;
-        KnuthElement nextElement = null;
-        // current InlineLevelLayoutManager
-        InlineLevelLayoutManager currLM = null;
-        // number of KnuthBox elements containing word fragments
-        int boxCount;
-        // number of auxiliary KnuthElements between KnuthBoxes
-        int auxCount;
-        StringBuffer sbChars = null;
-
-        // find all hyphenation points
-        while (currParIterator.hasNext()) {
-            firstElement = (KnuthElement) currParIterator.next();
-            // 
-            if (firstElement.getLayoutManager() != currLM) {
-                currLM = (InlineLevelLayoutManager) firstElement.getLayoutManager();
-                if (currLM != null) { 
-                    updateList.add(new Update(currLM, currParIterator.previousIndex()));
-                } else {
-                    break;
-                }
-            }
-
-            // collect word fragments, ignoring auxiliary elements;
-            // each word fragment was created by a different TextLM
-            if (firstElement.isBox() && !firstElement.isAuxiliary()) {
-                boxCount = 1;
-                auxCount = 0;
-                sbChars = new StringBuffer();
-                currLM.getWordChars(sbChars, firstElement.getPosition());
-                // look if next elements are boxes too
-                while (currParIterator.hasNext()) {
-                    nextElement = (KnuthElement) currParIterator.next();
-                    if (nextElement.isBox() && !nextElement.isAuxiliary()) {
-                        // a non-auxiliary KnuthBox: append word chars
-                        if (currLM != nextElement.getLayoutManager()) {
-                            currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager();
-                            updateList.add(new Update(currLM, currParIterator.previousIndex()));
-                        }
-                        // append text to recreate the whole word
-                        boxCount ++;
-                        currLM.getWordChars(sbChars, nextElement.getPosition());
-                    } else if (!nextElement.isAuxiliary()) {
-                        // a non-auxiliary non-box KnuthElement: stop
-                        // go back to the last box or auxiliary element
-                        currParIterator.previous(); 
-                        break;
-                    } else {
-                        // an auxiliary KnuthElement: simply ignore it
-                        auxCount ++;
-                    }
-                }
-                log.trace(" Word to hyphenate: " + sbChars.toString());
-                // find hyphenation points
-                HyphContext hc = getHyphenContext(sbChars);
-                // ask each LM to hyphenate its word fragment
-                if (hc != null) {
-                    KnuthElement element = null;
-                    for (int i = 0; i < (boxCount + auxCount); i++) {
-                        currParIterator.previous();
-                    }
-                    for (int i = 0; i < (boxCount + auxCount); i++) {
-                        element = (KnuthElement) currParIterator.next();
-                        if (element.isBox() && !element.isAuxiliary()) {
-                            ((InlineLevelLayoutManager)
-                             element.getLayoutManager()).hyphenate(element.getPosition(), hc);
-                        } else {
-                            // nothing to do, element is an auxiliary KnuthElement
-                        }
-                    }
-                }
-            }
-        }
-
-        // create iterator for the updateList
-        ListIterator updateListIterator = updateList.listIterator();
-        Update currUpdate = null;
-        //int iPreservedElements = 0;
-        int iAddedElements = 0;
-        //int iRemovedElements = 0;
-
-        while (updateListIterator.hasNext()) {
-            // ask the LMs to apply the changes and return 
-            // the new KnuthElements to replace the old ones
-            currUpdate = (Update) updateListIterator.next();
-            int fromIndex = currUpdate.iFirstIndex;
-            int toIndex;
-            if (updateListIterator.hasNext()) {
-                Update nextUpdate = (Update) updateListIterator.next();
-                toIndex = nextUpdate.iFirstIndex;
-                updateListIterator.previous();
-            } else {
-                // maybe this is not always correct!
-                toIndex = currPar.size() - currPar.ignoreAtEnd
-                    - iAddedElements;
-            }
-
-            // applyChanges() returns true if the LM modifies its data,
-            // so it must return new KnuthElements to replace the old ones
-            if (((InlineLevelLayoutManager) currUpdate.inlineLM)
-                .applyChanges(currPar.subList(fromIndex + iAddedElements,
-                                              toIndex + iAddedElements))) {
-                // insert the new KnuthElements
-                LinkedList newElements = null;
-                newElements
-                    = currUpdate.inlineLM.getChangedKnuthElements
-                    (currPar.subList(fromIndex + iAddedElements,
-                                     toIndex + iAddedElements),
-                     /*flaggedPenalty,*/ effectiveAlignment);
-                // remove the old elements
-                currPar.subList(fromIndex + iAddedElements,
-                                toIndex + iAddedElements).clear();
-                // insert the new elements
-                currPar.addAll(fromIndex + iAddedElements, newElements);
-                iAddedElements += newElements.size() - (toIndex - fromIndex);
-            }
-        }
-        updateListIterator = null;
-        updateList.clear();
-    }
-
-    /** Line area is always considered to act as a fence. */
-    protected boolean hasLeadingFence(boolean bNotFirst) {
-        return true;
-    }
-
-    /** Line area is always considered to act as a fence. */
-    protected boolean hasTrailingFence(boolean bNotLast) {
-        return true;
-    }
-
-    private HyphContext getHyphenContext(StringBuffer sbChars) {
-        // Find all hyphenation points in this word
-        // (get in an array of offsets)
-        // hyphProps are from the block level?.
-        // Note that according to the spec,
-        // they also "apply to" fo:character.
-        // I don't know what that means, since
-        // if we change language in the middle of a "word",
-        // the effect would seem quite strange!
-        // Or perhaps in that case, we say that it's several words.
-        // We probably should bring the hyphenation props up from the actual
-        // TextLM which generate the hyphenation buffer,
-        // since these properties inherit and could be specified
-        // on an inline or wrapper below the block level.
-        Hyphenation hyph
-            = Hyphenator.hyphenate(hyphProps.language,
-                                   hyphProps.country, sbChars.toString(),
-                                   hyphProps.hyphenationRemainCharacterCount,
-                                   hyphProps.hyphenationPushCharacterCount);
-        // They hyph structure contains the information we need
-        // Now start from prev: reset to that position, ask that LM to get
-        // a Position for the first hyphenation offset. If the offset isn't in
-        // its characters, it returns null,
-        // but must tell how many chars it had.
-        // Keep looking at currentBP using next hyphenation point until the
-        // returned size is greater than the available size
-        // or no more hyphenation points remain. Choose the best break.
-        if (hyph != null) {
-            return new HyphContext(hyph.getHyphenationPoints());
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Reset the positions to the given position.
-     *
-     * @param resetPos the position to reset to
-     */
-    public void resetPosition(Position resetPos) {
-        if (resetPos == null) {
-            setFinished(false);
-            iReturnedLBP = 0;
-        } else {
-            if (isFinished()) {
-                // if isFinished is true, iReturned LBP == breakpoints.size()
-                // and breakpoints.get(iReturnedLBP) would generate
-                // an IndexOutOfBoundException
-                setFinished(false);
-                iReturnedLBP--;
-            }
-            while ((LineBreakPosition) lineLayouts.getChosenPosition(iReturnedLBP)
-                   != (LineBreakPosition) resetPos) {
-                iReturnedLBP--;
-            }
-            iReturnedLBP++;
-        }
-    }
-
-    /**
-     * Add the areas with the break points.
-     *
-     * @param parentIter the iterator of break positions
-     * @param context the context for adding areas
-     */
-    public void addAreas(PositionIterator parentIter,
-                         LayoutContext context) {
-        LayoutManager childLM;
-        LayoutContext lc = new LayoutContext(0);
-        int iCurrParIndex;
-        while (parentIter.hasNext()) {
-            Position pos = (Position) parentIter.next();
-            if (pos instanceof LineBreakPosition) {
-                ListIterator paragraphIterator = null;
-                KnuthElement tempElement = null;
-                // the TLM which created the last KnuthElement in this line
-                LayoutManager lastLM = null;
-    
-                LineBreakPosition lbp = (LineBreakPosition) pos;
-                LineArea lineArea = new LineArea();
-                lineArea.setStartIndent(lbp.startIndent);
-                lineArea.setBPD(lbp.lineHeight);
-                lc.setBaseline(lbp.baseline);
-                lc.setLineHeight(lbp.lineHeight);
-                lc.setMiddleShift(middleShift);
-                lc.setTopShift(lbp.topShift);
-                lc.setBottomShift(lbp.bottomShift);
-
-                iCurrParIndex = lbp.iParIndex;
-                Paragraph currPar = (Paragraph) 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))
-                    ? currPar.ignoreAtEnd : 0;
-    
-                // ignore the last element in the line if it is a KnuthGlue object
-                paragraphIterator = currPar.listIterator(iEndElement);
-                tempElement = (KnuthElement) paragraphIterator.next();
-                if (tempElement.isGlue()) {
-                    iEndElement --;
-                    // this returns the same KnuthElement
-                    paragraphIterator.previous();
-                    tempElement = (KnuthElement) paragraphIterator.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();
-                    iStartElement ++;
-                }
-    
-                // Add the inline areas to lineArea
-                PositionIterator inlinePosIter
-                    = new KnuthPossPosIter(currPar, iStartElement,
-                                           iEndElement + 1);
-    
-                iStartElement = lbp.getLeafPos() + 1;
-                if (iStartElement == currPar.size()) {
-                    // advance to next paragraph
-                    iStartElement = 0;
-                }
-    
-                lc.setSpaceAdjust(lbp.dAdjust);
-                lc.setIPDAdjust(lbp.ipdAdjust);
-                lc.setLeadingSpace(new SpaceSpecifier(true));
-                lc.setTrailingSpace(new SpaceSpecifier(false));
-                lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
-
-                /* extension (not in the XSL FO recommendation): if the left and right margins
-                   have been optimized, recompute indents and / or adjust ratio, according
-                   to the paragraph horizontal alignment */
-                if (false && bTextAlignment == EN_JUSTIFY) {
-                    // re-compute space adjust ratio
-                    int updatedDifference = context.getStackLimit().opt - lbp.lineWidth + lbp.difference;
-                    double updatedRatio = 0.0;
-                    if (updatedDifference > 0) {
-                        updatedRatio = (float) updatedDifference / lbp.availableStretch;
-                    } else if (updatedDifference < 0) {
-                        updatedRatio = (float) updatedDifference / lbp.availableShrink;
-                    }
-                    lc.setIPDAdjust(updatedRatio);
-                    //System.out.println("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
-                    //System.out.println("              old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
-                } else if (false && bTextAlignment == EN_CENTER) {
-                    // re-compute indent
-                    int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth) / 2;
-                    lineArea.setStartIndent(updatedIndent);
-                } else if (false && bTextAlignment == EN_END) {
-                    // re-compute indent
-                    int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth);
-                    lineArea.setStartIndent(updatedIndent);
-                }
-
-                setCurrentArea(lineArea);
-                setChildContext(lc);
-                while ((childLM = inlinePosIter.getNextChildLM()) != null) {
-                    lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
-                    childLM.addAreas(inlinePosIter, lc);
-                    lc.setLeadingSpace(lc.getTrailingSpace());
-                    lc.setTrailingSpace(new SpaceSpecifier(false));
-                }
-                
-                // when can this be null?
-                // if display-align is distribute, add space after 
-                if (context.getSpaceAfter() > 0
-                    && (!context.isLastArea() || parentIter.hasNext())) {
-                    lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
-                }
-                parentLM.addChildArea(lineArea);
-            } else {
-                // pos was the Position inside a penalty item, nothing to do
-            }
-        }
-        setCurrentArea(null); // ?? necessary
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/LineLayoutPossibilities.java b/src/java/org/apache/fop/layoutmgr/LineLayoutPossibilities.java
deleted file mode 100644 (file)
index 865121f..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2004-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.layoutmgr;
-
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-public class LineLayoutPossibilities {
-
-    /** logger instance */
-    protected static Log log = LogFactory.getLog(LineLayoutPossibilities.class);
-    
-    private class Possibility {
-        private int lineCount;
-        private double demerits;
-        private List breakPositions;
-
-        private Possibility(int lc, double dem) {
-            lineCount = lc;
-            demerits = dem;
-            breakPositions = new java.util.ArrayList(lc);
-        }
-
-        private int getLineCount() {
-            return lineCount;
-        }
-
-        private double getDemerits() {
-            return demerits;
-        }
-
-        private void addBreakPosition(Position pos) {
-            // Positions are always added with index 0 because 
-            // they are created backward, from the last one to 
-            // the first one
-            breakPositions.add(0, pos);
-        }
-
-        private Position getBreakPosition(int i) {
-            return (Position)breakPositions.get(i);
-        }
-    }
-
-    private List possibilitiesList;
-    private List savedPossibilities;
-    private int minimumIndex;
-    private int optimumIndex;
-    private int maximumIndex;
-    private int chosenIndex;
-    private int savedOptLineCount;
-
-    public LineLayoutPossibilities() {
-        possibilitiesList = new java.util.ArrayList();
-        savedPossibilities = new java.util.ArrayList();
-        optimumIndex = -1;
-    }
-    public void addPossibility(int ln, double dem) {
-        possibilitiesList.add(new Possibility(ln, dem));
-        if (possibilitiesList.size() == 1) {
-            // first Possibility added
-            minimumIndex = 0;
-            optimumIndex = 0;
-            maximumIndex = 0;
-            chosenIndex = 0;
-        } else {
-            if (dem < ((Possibility)possibilitiesList.get(optimumIndex)).getDemerits()) {
-                optimumIndex = possibilitiesList.size() - 1;
-                chosenIndex = optimumIndex;
-            }
-            if (ln < ((Possibility)possibilitiesList.get(minimumIndex)).getLineCount()) {
-                minimumIndex = possibilitiesList.size() - 1;
-            }
-            if (ln > ((Possibility)possibilitiesList.get(maximumIndex)).getLineCount()) {
-                maximumIndex = possibilitiesList.size() - 1;
-            }
-        }
-    }
-
-    /* save in a different array the computed Possibilities,
-     * so possibilitiesList is ready to store different Possibilities
-     */
-    public void savePossibilities(boolean bSaveOptLineCount) {
-        if (bSaveOptLineCount) {
-            savedOptLineCount = getOptLineCount();
-        } else {
-            savedOptLineCount = 0;
-        }
-        savedPossibilities = possibilitiesList;
-        possibilitiesList = new java.util.ArrayList();
-    }
-
-    /* replace the Possibilities stored in possibilitiesList with
-     * the ones stored in savedPossibilities and having the same line number
-     */
-    public void restorePossibilities() {
-        int index = 0;
-        while (savedPossibilities.size() > 0) {
-            Possibility restoredPossibility = (Possibility) savedPossibilities.remove(0);
-            if (restoredPossibility.getLineCount() < getMinLineCount()) {
-                // if the line number of restoredPossibility is less than the minimum one,
-                // add restoredPossibility at the beginning of the list
-                possibilitiesList.add(0, restoredPossibility);
-                // update minimumIndex
-                minimumIndex = 0;
-                // shift the other indexes;
-                optimumIndex ++;
-                maximumIndex ++;
-                chosenIndex ++;
-            } else if (restoredPossibility.getLineCount() > getMaxLineCount()) {
-                // if the line number of restoredPossibility is greater than the maximum one,
-                // add restoredPossibility at the end of the list
-                possibilitiesList.add(possibilitiesList.size(), restoredPossibility);
-                // update maximumIndex
-                maximumIndex = possibilitiesList.size() - 1;
-                index = maximumIndex;
-            } else {
-                // find the index of the Possibility that will be replaced
-                while (index < maximumIndex
-                       && getLineCount(index) < restoredPossibility.getLineCount()) {
-                    index ++;
-                }
-                if (getLineCount(index) == restoredPossibility.getLineCount()) {
-                    possibilitiesList.set(index, restoredPossibility);
-                } else {
-                    // this should not happen
-                    log.error("LineLayoutPossibilities restorePossibilities(),"
-                        + " min= " + getMinLineCount() 
-                        + " max= " + getMaxLineCount() 
-                        + " restored= " + restoredPossibility.getLineCount());
-                    return;
-                }
-            }
-            // update optimumIndex and chosenIndex
-            if (savedOptLineCount == 0 && getDemerits(optimumIndex) > restoredPossibility.getDemerits()
-                || savedOptLineCount != 0 && restoredPossibility.getLineCount() == savedOptLineCount) {
-                optimumIndex = index;
-                chosenIndex = optimumIndex;
-            }
-        }
-/*LF*/  //System.out.println(">> minLineCount = " + getMinLineCount() + " optLineCount = " + getOptLineCount() + " maxLineCount() = " + getMaxLineCount());
-    }
-
-    public void addBreakPosition(Position pos, int i) {
-        ((Possibility)possibilitiesList.get(i)).addBreakPosition(pos);
-    }
-
-    public boolean canUseMoreLines() {
-        return (getOptLineCount() < getMaxLineCount());
-    }
-
-    public boolean canUseLessLines() {
-        return (getMinLineCount() < getOptLineCount());
-    }
-
-    public int getMinLineCount() {
-        return getLineCount(minimumIndex);
-    }
-
-    public int getOptLineCount() {
-        return getLineCount(optimumIndex);
-    }
-
-    public int getMaxLineCount() {
-        return getLineCount(maximumIndex);
-    }
-
-    public int getChosenLineCount() {
-        return getLineCount(chosenIndex);
-    }
-
-    public int getLineCount(int i) {
-        return ((Possibility)possibilitiesList.get(i)).getLineCount();
-    }
-
-    public double getChosenDemerits() {
-        return getDemerits(chosenIndex);
-    }
-
-    public double getDemerits(int i) {
-        return ((Possibility)possibilitiesList.get(i)).getDemerits();
-    }
-
-    public int getPossibilitiesNumber() {
-        return possibilitiesList.size();
-    }
-
-    public Position getChosenPosition(int i) {
-        return ((Possibility)possibilitiesList.get(chosenIndex)).getBreakPosition(i);
-    }
-
-    public int applyLineCountAdjustment(int adj) {
-        if (adj >= (getMinLineCount() - getChosenLineCount())
-            && adj <= (getMaxLineCount() - getChosenLineCount())
-            && getLineCount(chosenIndex + adj) == getChosenLineCount() + adj) {
-            chosenIndex += adj;
-            log.debug("chosenLineCount= " + (getChosenLineCount() - adj) + " adjustment= " + adj
-                               + " => chosenLineCount= " + getLineCount(chosenIndex));
-            return adj;
-        } else {
-            // this should not happen!
-            log.warn("Cannot apply the desired line count adjustment.");
-            return 0;
-        }
-    }
-
-    public void printAll() {
-        System.out.println("++++++++++");
-        System.out.println(" " + possibilitiesList.size() + " possibility':");
-        for (int i = 0; i < possibilitiesList.size(); i ++) {
-            System.out.println("   " + ((Possibility)possibilitiesList.get(i)).getLineCount()
-                               + (i == optimumIndex ? " *" : "")
-                               + (i == minimumIndex ? " -" : "")
-                               + (i == maximumIndex ? " +" : ""));
-        }
-        System.out.println("++++++++++");
-    }
-}
diff --git a/src/java/org/apache/fop/layoutmgr/PageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageNumberCitationLayoutManager.java
deleted file mode 100644 (file)
index f8530b8..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.fo.flow.PageNumberCitation;
-import org.apache.fop.area.PageViewport;
-import org.apache.fop.area.Resolvable;
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.UnresolvedPageNumber;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.fonts.Font;
-
-/**
- * LayoutManager for the fo:page-number-citation formatting object
- */
-public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager {
-
-    private PageNumberCitation fobj;
-    private Font font;
-    
-    // whether the page referred to by the citation has been resolved yet
-    private boolean resolved = false;
-    
-    /**
-     * Constructor
-     *
-     * @param node the formatting object that creates this area
-     * @todo better retrieval of font info
-     */
-    public PageNumberCitationLayoutManager(PageNumberCitation node) {
-        super(node);
-        fobj = node;
-        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
-    }
-
-    public InlineArea get(LayoutContext context) {
-        curArea = getPageNumberCitationInlineArea(parentLM);
-        return curArea;
-    }
-    
-    public void addAreas(PositionIterator posIter, LayoutContext context) {
-        super.addAreas(posIter, context);
-        if (!resolved) {
-            getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable) curArea);
-        }
-    }
-    
-    /** @see org.apache.fop.layoutmgr.LeafNodeLayoutManager#getLead() */
-    public int getLead() {
-        return font.getAscender();
-    }
-
-    protected void offsetArea(InlineArea area, LayoutContext context) {
-        area.setOffset(context.getBaseline());
-    }
-
-    /**
-     * if id can be resolved then simply return a word, otherwise
-     * return a resolvable area
-     */
-    private InlineArea getPageNumberCitationInlineArea(LayoutManager parentLM) {
-        PageViewport page = getPSLM().getFirstPVWithID(fobj.getRefId());
-        InlineArea inline = null;
-        if (page != null) {
-            String str = page.getPageNumberString();
-            // get page string from parent, build area
-            TextArea text = new TextArea();
-            inline = text;
-            int width = getStringWidth(str);
-            text.setTextArea(str);
-            inline.setIPD(width);
-            
-            resolved = true;
-        } else {
-            resolved = false;
-            inline = new UnresolvedPageNumber(fobj.getRefId());
-            String str = "MMM"; // reserve three spaces for page number
-            int width = getStringWidth(str);
-            inline.setIPD(width);
-            
-        }
-        inline.setBPD(font.getAscender() - font.getDescender());
-        inline.setOffset(font.getAscender());
-        inline.addTrait(Trait.FONT_NAME, font.getFontName());
-        inline.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize()));
-        TraitSetter.addTextDecoration(inline, fobj.getTextDecoration());
-        
-        return inline;
-    }
-    
-    /**
-     * @param str string to be measured
-     * @return width (in millipoints ??) of the string
-     */
-    private int getStringWidth(String str) {
-        int width = 0;
-        for (int count = 0; count < str.length(); count++) {
-            width += font.getCharWidth(str.charAt(count));
-        }
-        return width;
-    }
-    
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/PageNumberLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageNumberLayoutManager.java
deleted file mode 100644 (file)
index bbe8b4f..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import org.apache.fop.fo.flow.PageNumber;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.area.Trait;
-import org.apache.fop.fonts.Font;
-
-/**
- * LayoutManager for the fo:page-number formatting object
- */
-public class PageNumberLayoutManager extends LeafNodeLayoutManager {
-    
-    private PageNumber fobj;
-    private Font font;
-    
-    /**
-     * Constructor
-     *
-     * @param node the fo:page-number formatting object that creates the area
-     * @todo better null checking of node, font
-     */
-    public PageNumberLayoutManager(PageNumber node) {
-        super(node);
-        fobj = node;
-        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
-    }
-
-    public InlineArea get(LayoutContext context) {
-        // get page string from parent, build area
-        TextArea inline = new TextArea();
-        String str = getCurrentPV().getPageNumberString();
-        int width = 0;
-        for (int count = 0; count < str.length(); count++) {
-            width += font.getCharWidth(str.charAt(count));
-        }
-        inline.setTextArea(str);
-        inline.setIPD(width);
-        inline.setBPD(font.getAscender() - font.getDescender());
-        inline.setOffset(font.getAscender());
-        inline.addTrait(Trait.FONT_NAME, font.getFontName());
-        inline.addTrait(Trait.FONT_SIZE,
-                        new Integer(font.getFontSize()));
-
-        TraitSetter.addTextDecoration(inline, fobj.getTextDecoration());
-
-        return inline;
-    }
-    
-    
-    /** @see org.apache.fop.layoutmgr.LeafNodeLayoutManager#getLead() */
-    public int getLead() {
-        return font.getAscender();
-    }
-    
-    protected void offsetArea(InlineArea area, LayoutContext context) {
-        area.setOffset(context.getBaseline());
-    }
-    
-    protected InlineArea getEffectiveArea() {
-        TextArea baseArea = (TextArea)curArea;
-        //TODO Maybe replace that with a clone() call or better, a copy constructor
-        //TODO or even better: delay area creation until addAreas() stage
-        //TextArea is cloned because the LM is reused in static areas and the area can't be.
-        TextArea ta = new TextArea();
-        ta.setIPD(baseArea.getIPD());
-        ta.setBPD(baseArea.getBPD());
-        ta.setOffset(baseArea.getOffset());
-        ta.addTrait(Trait.FONT_NAME, font.getFontName()); //only to initialize the trait map
-        ta.getTraits().putAll(baseArea.getTraits());
-        updateContent(ta);
-        return ta;
-    }
-    
-    private void updateContent(TextArea area) {
-        area.setTextArea(getCurrentPV().getPageNumberString());
-    }
-    
-    protected void addId() {
-        getPSLM().addIDToPage(fobj.getId());
-    }
-}
-
index d8014787dd1f93ccf1e013ddb7f051102661484d..493cac7d877fef8d11f117da44ea4336de48d14d 100644 (file)
@@ -40,6 +40,7 @@ import org.apache.fop.fo.pagination.Region;
 import org.apache.fop.fo.pagination.SideRegion;
 import org.apache.fop.fo.pagination.SimplePageMaster;
 import org.apache.fop.fo.pagination.StaticContent;
+import org.apache.fop.layoutmgr.inline.ContentLayoutManager;
 
 import org.apache.fop.traits.MinOptMax;
 
index 841634ef458d242c548d84ff5b2d23b3d3f6c5cd..5412d80fc3c50f74d19797892dfe09734f9c30f9 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.fop.area.Block;
 import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.pagination.SideRegion;
 import org.apache.fop.fo.pagination.StaticContent;
+import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
 import org.apache.fop.traits.MinOptMax;
 
 /**
diff --git a/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/TextLayoutManager.java
deleted file mode 100644 (file)
index d545f30..0000000
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright 1999-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.layoutmgr;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.LinkedList;
-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.traits.SpaceVal;
-import org.apache.fop.area.Trait;
-import org.apache.fop.area.inline.InlineArea;
-import org.apache.fop.area.inline.TextArea;
-import org.apache.fop.traits.MinOptMax;
-
-/**
- * LayoutManager for text (a sequence of characters) which generates one
- * or more inline areas.
- */
-public class TextLayoutManager extends LeafNodeLayoutManager {
-
-    /**
-     * Store information about each potential text area.
-     * Index of character which ends the area, IPD of area, including
-     * any word-space and letter-space.
-     * Number of word-spaces?
-     */
-    private class AreaInfo {
-        private short iStartIndex;
-        private short iBreakIndex;
-        private short iWScount;
-        private short iLScount;
-        private MinOptMax ipdArea;
-        private boolean bHyphenated;
-        public AreaInfo(short iSIndex, short iBIndex, short iWS, short iLS,
-                        MinOptMax ipd, boolean bHyph) {
-            iStartIndex = iSIndex;
-            iBreakIndex = iBIndex;
-            iWScount = iWS;
-            iLScount = iLS;
-            ipdArea = ipd;
-            bHyphenated = bHyph;
-        }
-    }
-
-    // this class stores information about changes in vecAreaInfo
-    // which are not yet applied
-    private class PendingChange {
-        public AreaInfo ai;
-        public int index;
-
-        public PendingChange(AreaInfo ai, int index) {
-            this.ai = ai;
-            this.index = index;
-        }
-    }
-
-    // Hold all possible breaks for the text in this LM's FO.
-    private ArrayList vecAreaInfo;
-
-    /** Non-space characters on which we can end a line. */
-    private static final String BREAK_CHARS = "-/" ;
-
-    private FOText foText;
-    private char[] textArray;
-
-    private static final char NEWLINE = '\n';
-    private static final char SPACE = '\u0020'; // Normal space
-    private static final char NBSPACE = '\u00A0'; // Non-breaking space
-    private static final char LINEBREAK = '\u2028';
-    private static final char ZERO_WIDTH_SPACE = '\u200B';
-    // byte order mark
-    private static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
-
-    /** Start index of first character in this parent Area */
-    private short iAreaStart = 0;
-    /** Start index of next TextArea */
-    private short iNextStart = 0;
-    /** Size since last makeArea call, except for last break */
-    private MinOptMax ipdTotal;
-    /** Size including last break possibility returned */
-    // private MinOptMax nextIPD = new MinOptMax(0);
-    /** size of a space character (U+0020) glyph in current font */
-    private int spaceCharIPD;
-    private MinOptMax wordSpaceIPD;
-    private MinOptMax letterSpaceIPD;
-    /** size of the hyphen character glyph in current font */
-    private int hyphIPD;
-    /** 1/2 of word-spacing value */
-    private SpaceVal halfWS;
-    /** Number of space characters after previous possible break position. */
-    private int iNbSpacesPending;
-    private Font fs;
-
-    private boolean bChanged = false;
-    private int iReturnedIndex = 0;
-    private short iThisStart = 0;
-    private short iTempStart = 0;
-    private LinkedList changeList = null;
-
-    private int textHeight;
-    private int lead = 0;
-    private int total = 0;
-    private int middle = 0;
-    private int verticalAlignment = EN_BASELINE;
-
-    /**
-     * Create a Text layout manager.
-     *
-     * @param node The FOText object to be rendered
-     */
-    public TextLayoutManager(FOText node) {
-        super();
-        foText = node;
-        
-        textArray = new char[node.endIndex - node.startIndex];
-        System.arraycopy(node.ca, node.startIndex, textArray, 0,
-            node.endIndex - node.startIndex);
-
-        vecAreaInfo = new java.util.ArrayList();
-
-        fs = foText.getCommonFont().getFontState(foText.getFOEventHandler().getFontInfo());
-        
-        // With CID fonts, space isn't neccesary currentFontState.width(32)
-        spaceCharIPD = fs.getCharWidth(' ');
-        // Use hyphenationChar property
-        hyphIPD = fs.getCharWidth(foText.getCommonHyphenation().hyphenationCharacter);
-        // Make half-space: <space> on either side of a word-space)
-        SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
-        SpaceVal ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, fs);
-        halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
-                ws.isConditional(), ws.isForcing(), ws.getPrecedence());
-
-        // letter space applies only to consecutive non-space characters,
-        // while word space applies to space characters;
-        // i.e. the spaces in the string "A SIMPLE TEST" are:
-        //      A<<ws>>S<ls>I<ls>M<ls>P<ls>L<ls>E<<ws>>T<ls>E<ls>S<ls>T
-        // there is no letter space after the last character of a word,
-        // nor after a space character
-
-        // set letter space and word space dimension;
-        // the default value "normal" was converted into a MinOptMax value
-        // in the SpaceVal.makeWordSpacing() method
-        letterSpaceIPD = ls.getSpace();
-        wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws.getSpace());
-
-        // set text height
-        textHeight = fs.getAscender()
-                     - fs.getDescender();
-
-        // if the text node is son of an inline, set vertical align
-        if (foText.getParent() instanceof Inline) {
-            setAlignment(((Inline) foText.getParent()).getVerticalAlign());
-        }
-        switch (verticalAlignment) {
-            case EN_MIDDLE  : middle = textHeight / 2 ;
-                                         break;
-            case EN_TOP     : // fall through
-            case EN_BOTTOM  : total = textHeight;
-                                         break;
-            case EN_BASELINE: // fall through
-            default                    : lead = fs.getAscender();
-                                         total = textHeight;
-                                         break;
-        }
-    }
-
-    /**
-     * Reset position for returning next BreakPossibility.
-     *
-     * @param prevPos the position to reset to
-     */
-    public void resetPosition(Position prevPos) {
-        if (prevPos != null) {
-            // ASSERT (prevPos.getLM() == this)
-            if (prevPos.getLM() != this) {
-                log.error("TextLayoutManager.resetPosition: "
-                          + "LM mismatch!!!");
-            }
-            LeafPosition tbp = (LeafPosition) prevPos;
-            AreaInfo ai =
-              (AreaInfo) vecAreaInfo.get(tbp.getLeafPos());
-            if (ai.iBreakIndex != iNextStart) {
-                iNextStart = ai.iBreakIndex;
-                vecAreaInfo.ensureCapacity(tbp.getLeafPos() + 1);
-                // TODO: reset or recalculate total IPD = sum of all word IPD
-                // up to the break position
-                ipdTotal = ai.ipdArea;
-                setFinished(false);
-            }
-        } else {
-            // Reset to beginning!
-            vecAreaInfo.clear();
-            iNextStart = 0;
-            setFinished(false);
-        }
-    }
-
-    // TODO: see if we can use normal getNextBreakPoss for this with
-    // extra hyphenation information in LayoutContext
-    private boolean getHyphenIPD(HyphContext hc, MinOptMax hyphIPD) {
-        // Skip leading word-space before calculating count?
-        boolean bCanHyphenate = true;
-        int iStopIndex = iNextStart + hc.getNextHyphPoint();
-
-        if (textArray.length < iStopIndex) {
-            iStopIndex = textArray.length;
-            bCanHyphenate = false;
-        }
-        hc.updateOffset(iStopIndex - iNextStart);
-
-        for (; iNextStart < iStopIndex; iNextStart++) {
-            char c = textArray[iNextStart];
-            hyphIPD.opt += fs.getCharWidth(c);
-            // letter-space?
-        }
-        // Need to include hyphen size too, but don't count it in the
-        // stored running total, since it would be double counted
-        // with later hyphenation points
-        return bCanHyphenate;
-    }
-
-    /**
-     * Generate and add areas to parent area.
-     * This can either generate an area for each TextArea and each space, or
-     * an area containing all text with a parameter controlling the size of
-     * the word space. The latter is most efficient for PDF generation.
-     * Set size of each area.
-     * @param posIter Iterator over Position information returned
-     * by this LayoutManager.
-     * @param context LayoutContext for adjustments
-     */
-    public void addAreas(PositionIterator posIter, LayoutContext context) {
-
-        // Add word areas
-        AreaInfo ai = null;
-        int iStart = -1;
-        int iWScount = 0;
-        int iLScount = 0;
-        MinOptMax realWidth = new MinOptMax(0);
-
-        /* On first area created, add any leading space.
-         * Calculate word-space stretch value.
-         */
-        while (posIter.hasNext()) {
-            LeafPosition tbpNext = (LeafPosition) posIter.next();
-            //
-            if (tbpNext.getLeafPos() != -1) {
-                ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos());
-                if (iStart == -1) {
-                    iStart = ai.iStartIndex;
-                }
-                iWScount += ai.iWScount;
-                iLScount += ai.iLScount;
-                realWidth.add(ai.ipdArea);
-            }
-        }
-        if (ai == null) {
-            return;
-        }
-
-        // Make an area containing all characters between start and end.
-        InlineArea word = null;
-        int adjust = 0;
-        
-        // ignore newline character
-        if (textArray[ai.iBreakIndex - 1] == NEWLINE) {
-            adjust = 1;
-        }
-        String str = new String(textArray, iStart,
-                                ai.iBreakIndex - iStart - adjust);
-
-        // add hyphenation character if the last word is hyphenated
-        if (context.isLastArea() && ai.bHyphenated) {
-            str += foText.getCommonHyphenation().hyphenationCharacter;
-            realWidth.add(new MinOptMax(hyphIPD));
-        }
-
-        // Calculate adjustments
-        int iDifference = 0;
-        int iTotalAdjust = 0;
-        int iWordSpaceDim = wordSpaceIPD.opt;
-        int iLetterSpaceDim = letterSpaceIPD.opt;
-        double dIPDAdjust = context.getIPDAdjust();
-        double dSpaceAdjust = context.getSpaceAdjust(); // not used
-
-        // calculate total difference between real and available width
-        if (dIPDAdjust > 0.0) {
-            iDifference = (int) ((double) (realWidth.max - realWidth.opt)
-                                * dIPDAdjust);
-        } else {
-            iDifference = (int) ((double) (realWidth.opt - realWidth.min)
-                                * dIPDAdjust);
-        }
-        
-        // set letter space adjustment
-        if (dIPDAdjust > 0.0) {
-            iLetterSpaceDim
-                += (int) ((double) (letterSpaceIPD.max - letterSpaceIPD.opt)
-                         * dIPDAdjust);
-        } else  {
-            iLetterSpaceDim
-                += (int) ((double) (letterSpaceIPD.opt - letterSpaceIPD.min)
-                         * dIPDAdjust);
-        }
-        iTotalAdjust += (iLetterSpaceDim - letterSpaceIPD.opt) * iLScount;
-
-        // set word space adjustment
-        // 
-        if (iWScount > 0) {
-            iWordSpaceDim += (int) ((iDifference - iTotalAdjust) / iWScount);
-        } else {
-            // there are no word spaces in this area
-        }
-        iTotalAdjust += (iWordSpaceDim - wordSpaceIPD.opt) * iWScount;
-
-        TextArea t = createTextArea(str, realWidth.opt + iTotalAdjust,
-                                    context);
-
-        // iWordSpaceDim is computed in relation to wordSpaceIPD.opt
-        // but the renderer needs to know the adjustment in relation
-        // to the size of the space character in the current font;
-        // moreover, the pdf renderer adds the character spacing even to
-        // the last character of a word and to space characters: in order
-        // to avoid this, we must subtract the letter space width twice;
-        // the renderer will compute the space width as:
-        //   space width = 
-        //     = "normal" space width + letterSpaceAdjust + wordSpaceAdjust
-        //     = spaceCharIPD + letterSpaceAdjust +
-        //       + (iWordSpaceDim - spaceCharIPD -  2 * letterSpaceAdjust)
-        //     = iWordSpaceDim - letterSpaceAdjust
-        t.setTextLetterSpaceAdjust(iLetterSpaceDim);
-        t.setTextWordSpaceAdjust(iWordSpaceDim - spaceCharIPD
-                                 - 2 * t.getTextLetterSpaceAdjust());
-        
-        word = t;
-        if (word != null) {
-            parentLM.addChildArea(word);
-        }
-    }
-
-    /**
-     * Create an inline word area.
-     * This creates a TextArea and sets up the various attributes.
-     *
-     * @param str the string for the TextArea
-     * @param width the width that the TextArea uses
-     * @param base the baseline position
-     * @return the new word area
-     */
-    protected TextArea createTextArea(String str, int width, LayoutContext context) {
-        TextArea textArea = new TextArea();
-        textArea.setIPD(width);
-        textArea.setBPD(fs.getAscender() - fs.getDescender());
-        int bpd = textArea.getBPD();
-        switch (verticalAlignment) {
-            case EN_MIDDLE:
-                textArea.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2);
-            break;
-            case EN_TOP:
-                textArea.setOffset(context.getTopBaseline() + fs.getAscender());
-            break;
-            case EN_BOTTOM:
-                textArea.setOffset(context.getBottomBaseline() - bpd + fs.getAscender());
-            break;
-            case EN_BASELINE:
-            default:
-                textArea.setOffset(context.getBaseline());
-            break;
-        }
-
-        textArea.setTextArea(str);
-        textArea.addTrait(Trait.FONT_NAME, fs.getFontName());
-        textArea.addTrait(Trait.FONT_SIZE, new Integer(fs.getFontSize()));
-        textArea.addTrait(Trait.COLOR, foText.getColor());
-        
-        TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
-        
-        return textArea;
-    }
-
-    /**
-     * Set the alignment of the inline area.
-     * @param al the vertical alignment positioning
-     */
-    public void setAlignment(int al) {
-        verticalAlignment = al;
-    }
-
-    public LinkedList getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
-        LinkedList returnList = new LinkedList();
-
-        while (iNextStart < textArray.length) {
-            if (textArray[iNextStart] == SPACE
-                || textArray[iNextStart] == NBSPACE) {
-                // normal, breaking space
-                // or non-breaking space
-                if (textArray[iNextStart] == NBSPACE) {
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, vecAreaInfo.size() - 1),
-                                          false));
-                }
-                switch (alignment) {
-                case EN_CENTER :
-                    vecAreaInfo.add
-                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
-                                      (short) 1, (short) 0,
-                                      wordSpaceIPD, false));
-                    returnList.add
-                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
-                        (new KnuthPenalty(0, 0, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthInlineBox(0, 0, 0, 0,
-                                      new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, -1), true));
-                    iNextStart ++;
-                    break;
-
-                case EN_START  : // fall through
-                case EN_END    :
-                    vecAreaInfo.add
-                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
-                                      (short) 1, (short) 0,
-                                      wordSpaceIPD, false));
-                    returnList.add
-                        (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0,
-                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
-                        (new KnuthPenalty(0, 0, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       - 3 * wordSpaceIPD.opt, 0,
-                                       new LeafPosition(this, -1), true));
-                    iNextStart ++;
-                    break;
-
-                case EN_JUSTIFY:
-                    vecAreaInfo.add
-                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
-                                      (short) 1, (short) 0,
-                                      wordSpaceIPD, false));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       wordSpaceIPD.max - wordSpaceIPD.opt,
-                                       wordSpaceIPD.opt - wordSpaceIPD.min,
-                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    iNextStart ++;
-                    break;
-
-                default:
-                    vecAreaInfo.add
-                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
-                                      (short) 1, (short) 0,
-                                      wordSpaceIPD, false));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       wordSpaceIPD.max - wordSpaceIPD.opt, 0,
-                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    iNextStart ++;
-                }
-            } else if (textArray[iNextStart] == NBSPACE) {
-                // non breaking space
-                vecAreaInfo.add
-                    (new AreaInfo(iNextStart, (short) (iNextStart + 1),
-                                  (short) 1, (short) 0,
-                                  wordSpaceIPD, false));
-                returnList.add
-                    (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                      new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                returnList.add
-                    (new KnuthGlue(wordSpaceIPD.opt,
-                                   wordSpaceIPD.max - wordSpaceIPD.opt,
-                                   wordSpaceIPD.opt - wordSpaceIPD.min,
-                                   new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                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
-                    (new KnuthPenalty(0, -KnuthElement.INFINITE,
-                                      false, null, false));
-                iNextStart ++;
-                return returnList;
-            } else {
-                // the beginning of a word
-                iThisStart = iNextStart;
-                iTempStart = iNextStart;
-                MinOptMax wordIPD = new MinOptMax(0);
-                for (; iTempStart < textArray.length
-                        && textArray[iTempStart] != SPACE
-                        && textArray[iTempStart] != NBSPACE
-                     && textArray[iTempStart] != NEWLINE
-                     && !(iTempStart > iNextStart
-                          && alignment == EN_JUSTIFY
-                          && BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0);
-                        iTempStart++) {
-                    wordIPD.add(fs.getCharWidth(textArray[iTempStart]));
-                }
-                int iLetterSpaces = iTempStart - iThisStart - 1;
-                wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
-                vecAreaInfo.add
-                    (new AreaInfo(iThisStart, iTempStart, (short) 0,
-                                  (short) iLetterSpaces,
-                                  wordIPD, false));
-                if (letterSpaceIPD.min == letterSpaceIPD.max) {
-                    // constant letter space; simply return a box
-                    // whose width includes letter spaces
-                    returnList.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
-                        (new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
-                                      lead, total, middle,
-                                      new LeafPosition(this, vecAreaInfo.size() - 1), false));
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
-                                       iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
-                                       iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
-                                       new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthInlineBox(0, lead, total, middle,
-                                            new LeafPosition(this, -1), true));
-                }
-                // if the last character is '-' or '/', it could be used as a line end;
-                // add a flagged penalty element and glue element representing a suppressible 
-                // letter space if the next character is not a space
-                if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0
-                    && iTempStart < textArray.length
-                    && textArray[iTempStart] != SPACE
-                    && textArray[iTempStart] != NBSPACE) {
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
-                                          new LeafPosition(this, -1), false));
-                    returnList.add
-                        (new KnuthGlue(letterSpaceIPD.opt,
-                                       letterSpaceIPD.max - letterSpaceIPD.opt,
-                                       letterSpaceIPD.opt - letterSpaceIPD.min,
-                                       new LeafPosition(this, -1), false));
-                    // update the information in the AreaInfo, adding one more letter space
-                    AreaInfo ai = (AreaInfo) vecAreaInfo.get(vecAreaInfo.size() - 1);
-                    ai.iLScount ++;
-                }
-                iNextStart = iTempStart;
-            }
-        } // end of while
-        setFinished(true);
-        if (returnList.size() > 0) {
-            return returnList;
-        } else {
-            return null;
-        }
-    }
-
-    public List addALetterSpaceTo(List oldList) {
-        // old list contains only a box, or the sequence: box penalty glue box;
-        // 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();
-        AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos());
-        ai.iLScount ++;
-        ai.ipdArea.add(letterSpaceIPD);
-        if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0) {
-            // the last character could be used as a line break
-            // append new elements to oldList
-            oldListIterator = oldList.listIterator(oldList.size());
-            oldListIterator.add(new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
-                                                 new LeafPosition(this, -1), false));
-            oldListIterator.add(new KnuthGlue(letterSpaceIPD.opt,
-                                       letterSpaceIPD.max - letterSpaceIPD.opt,
-                                       letterSpaceIPD.opt - letterSpaceIPD.min,
-                                       new LeafPosition(this, -1), false));
-        } else if (letterSpaceIPD.min == letterSpaceIPD.max) {
-            // constant letter space: replace the box
-            oldListIterator.set(new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle, pos, false));
-        } else {
-            // adjustable letter space: replace the glue
-            oldListIterator.next(); // this would return the penalty element
-            oldListIterator.next(); // this would return the glue element
-            oldListIterator.set(new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
-                                              ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
-                                              ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
-                                              new LeafPosition(this, -1), true));
-        }
-        return oldList;
-    }
-
-    public void hyphenate(Position pos, HyphContext hc) {
-        AreaInfo ai
-            = (AreaInfo) vecAreaInfo.get(((LeafPosition) pos).getLeafPos());
-        int iStartIndex = ai.iStartIndex;
-        int iStopIndex;
-        boolean bNothingChanged = true;
-
-        while (iStartIndex < ai.iBreakIndex) {
-            MinOptMax newIPD = new MinOptMax(0);
-            boolean bHyphenFollows;
-
-            if (hc.hasMoreHyphPoints()
-                && (iStopIndex = iStartIndex + hc.getNextHyphPoint())
-                <= ai.iBreakIndex) {
-                // iStopIndex is the index of the first character
-                // after a hyphenation point
-                bHyphenFollows = true;
-            } else {
-                // there are no more hyphenation points,
-                // or the next one is after ai.iBreakIndex
-                bHyphenFollows = false;
-                iStopIndex = ai.iBreakIndex;
-            }
-
-            hc.updateOffset(iStopIndex - iStartIndex);
-
-            for (int i = iStartIndex; i < iStopIndex; i++) {
-                char c = textArray[i];
-                newIPD.add(new MinOptMax(fs.getCharWidth(c)));
-            }
-            // add letter spaces
-            boolean bIsWordEnd
-                = iStopIndex == ai.iBreakIndex
-                && ai.iLScount < (ai.iBreakIndex - ai.iStartIndex);
-            newIPD.add(MinOptMax.multiply(letterSpaceIPD,
-                                          (bIsWordEnd
-                                           ? (iStopIndex - iStartIndex - 1)
-                                           : (iStopIndex - iStartIndex))));
-
-            if (!(bNothingChanged
-                  && iStopIndex == ai.iBreakIndex 
-                  && bHyphenFollows == false)) {
-                // the new AreaInfo object is not equal to the old one
-                if (changeList == null) {
-                    changeList = new LinkedList();
-                }
-                changeList.add
-                    (new PendingChange
-                     (new AreaInfo((short) iStartIndex, (short) iStopIndex,
-                                   (short) 0,
-                                   (short) (bIsWordEnd
-                                            ? (iStopIndex - iStartIndex - 1)
-                                            : (iStopIndex - iStartIndex)),
-                                   newIPD, bHyphenFollows),
-                      ((LeafPosition) pos).getLeafPos()));
-                bNothingChanged = false;
-            }
-            iStartIndex = iStopIndex;
-        }
-        if (!bChanged && !bNothingChanged) {
-            bChanged = true;
-        }
-    }
-
-    public boolean applyChanges(List oldList) {
-        setFinished(false);
-
-        if (changeList != null) {
-            int iAddedAI = 0;
-            int iRemovedAI = 0;
-            int iOldIndex = -1;
-            PendingChange currChange = null;
-            ListIterator changeListIterator = changeList.listIterator();
-            while (changeListIterator.hasNext()) {
-                currChange = (PendingChange) changeListIterator.next();
-                if (currChange.index != iOldIndex) {
-                    iRemovedAI ++;
-                    iAddedAI ++;
-                    iOldIndex = currChange.index;
-                    vecAreaInfo.remove(currChange.index + iAddedAI - iRemovedAI);
-                    vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI,
-                                    currChange.ai);
-                } else {
-                    iAddedAI ++;
-                    vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI,
-                                    currChange.ai);
-                }
-            }
-            changeList.clear();
-        }
-
-        iReturnedIndex = 0;
-        return bChanged;
-    }
-
-    public LinkedList getChangedKnuthElements(List oldList,
-                                              /*int flaggedPenalty,*/
-                                              int alignment) {
-        if (isFinished()) {
-            return null;
-        }
-
-        LinkedList returnList = new LinkedList();
-
-        while (iReturnedIndex < vecAreaInfo.size()) {
-            AreaInfo ai = (AreaInfo) vecAreaInfo.get(iReturnedIndex);
-            if (ai.iWScount == 0) {
-                // ai refers either to a word or a word fragment
-
-                // if the last character is '-' or '/' and the next character is not a space
-                // one of the letter spaces must be represented using a penalty and a glue,
-                // and its width must be subtracted
-                if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
-                    && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
-                    ai.ipdArea.add(new MinOptMax(-letterSpaceIPD.min, -letterSpaceIPD.opt, -letterSpaceIPD.max));
-                }
-                if (letterSpaceIPD.min == letterSpaceIPD.max) {
-                    returnList.add
-                        (new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle,
-                                      new LeafPosition(this, iReturnedIndex), false));
-                } else {
-                    returnList.add
-                        (new KnuthInlineBox(ai.ipdArea.opt
-                                      - ai.iLScount * letterSpaceIPD.opt,
-                                      lead, total, middle, 
-                                      new LeafPosition(this, iReturnedIndex), false));
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
-                                       ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
-                                       ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
-                                       new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthInlineBox(0, 0, 0, 0,
-                                      new LeafPosition(this, -1), true));
-                }
-                if (ai.bHyphenated) {
-                    returnList.add
-                        (new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true,
-                                          new LeafPosition(this, -1), false));
-                }
-                // if the last character is '-' or '/', it could be used as a line end;
-                // add a flagged penalty element and a glue element representing a suppressible 
-                // letter space if the next character is not a space
-                if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
-                    && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
-                                          new LeafPosition(this, -1), false));
-                    returnList.add
-                        (new KnuthGlue(letterSpaceIPD.opt,
-                                       letterSpaceIPD.max - letterSpaceIPD.opt,
-                                       letterSpaceIPD.opt - letterSpaceIPD.min,
-                                       new LeafPosition(this, -1), false));
-                }
-                iReturnedIndex ++;
-            } else {
-                // ai refers to a space
-                if (textArray[ai.iStartIndex] == NBSPACE) {
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, -1),
-                                          false));
-                }
-                switch (alignment) {
-                case EN_CENTER :
-                    returnList.add
-                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, iReturnedIndex), false));
-                    returnList.add
-                        (new KnuthPenalty(0, 0, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthInlineBox(0, 0, 0, 0,
-                                      new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, -1), true));
-                    iReturnedIndex ++;
-                    break;
-                case EN_START  : // fall through
-                case EN_END    :
-                    returnList.add
-                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, iReturnedIndex), false));
-                    returnList.add
-                        (new KnuthPenalty(0, 0, false,
-                                          new LeafPosition(this, -1), true));
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       - 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                       new LeafPosition(this, -1), true));
-                    iReturnedIndex ++;
-                    break;
-                case EN_JUSTIFY:
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       wordSpaceIPD.max - wordSpaceIPD.opt,
-                                       wordSpaceIPD.opt - wordSpaceIPD.min,
-                                       new LeafPosition(this, iReturnedIndex), false));
-                    iReturnedIndex ++;
-                    break;
-                    
-                default:
-                    returnList.add
-                        (new KnuthGlue(wordSpaceIPD.opt,
-                                       wordSpaceIPD.max - wordSpaceIPD.opt, 0,
-                                       new LeafPosition(this, iReturnedIndex), false));
-                    iReturnedIndex ++;
-                }
-            }
-        } // end of while
-        setFinished(true);
-        return returnList;
-    }
-
-    public void getWordChars(StringBuffer sbChars, Position pos) {
-        int iLeafValue = ((LeafPosition) pos).getLeafPos();
-        if (iLeafValue != -1) {
-            AreaInfo ai = (AreaInfo) vecAreaInfo.get(iLeafValue);
-            sbChars.append(new String(textArray, ai.iStartIndex,
-                                      ai.iBreakIndex - ai.iStartIndex));
-        }
-    }
-}
-
diff --git a/src/java/org/apache/fop/layoutmgr/WrapperLayoutManager.java b/src/java/org/apache/fop/layoutmgr/WrapperLayoutManager.java
deleted file mode 100644 (file)
index e7341b8..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*\r
- * Copyright 2005 The Apache Software Foundation.\r
- * \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-/* $Id$ */\r
-\r
-package org.apache.fop.layoutmgr;\r
-\r
-import org.apache.fop.area.inline.InlineArea;\r
-import org.apache.fop.fo.flow.Wrapper;\r
-\r
-/**\r
- * This is the layout manager for the fo:wrapper formatting object.\r
- */\r
-public class WrapperLayoutManager extends LeafNodeLayoutManager {\r
-    \r
-    private Wrapper fobj;\r
-\r
-    /**\r
-     * Creates a new LM for fo:wrapper.\r
-     * @param node the fo:wrapper\r
-     */\r
-    public WrapperLayoutManager(Wrapper node) {\r
-        super(node);\r
-        fobj = node;\r
-    }\r
-\r
-    /** @see org.apache.fop.layoutmgr.LeafNodeLayoutManager */\r
-    public InlineArea get(LayoutContext context) {\r
-        //Create a zero-width, zero-height dummy area so this node can \r
-        //participate in the ID handling. Otherwise, addId() wouldn't \r
-        //be called.\r
-        InlineArea area = new InlineArea();\r
-        return area;\r
-    }\r
-    \r
-    /** @see org.apache.fop.layoutmgr.LeafNodeLayoutManager#addId() */\r
-    protected void addId() {\r
-        getPSLM().addIDToPage(fobj.getId());\r
-    }\r
-    \r
-}\r
diff --git a/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BasicLinkLayoutManager.java
new file mode 100644 (file)
index 0000000..9dd0abb
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+import org.apache.fop.fo.flow.BasicLink;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.area.inline.InlineParent;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.LinkResolver;
+import org.apache.fop.area.PageViewport;
+
+/**
+ * LayoutManager for the fo:basic-link formatting object
+ */
+public class BasicLinkLayoutManager extends InlineLayoutManager {
+    private BasicLink fobj;
+    
+    /**
+     * Create an fo:basic-link layout manager.
+     *
+     * @param node the formatting object that creates the area
+     */
+    public BasicLinkLayoutManager(BasicLink node) {
+        super(node);
+        fobj = node;
+    }
+
+    protected InlineParent createArea() {
+        InlineParent area = super.createArea();
+        setupBasicLinkArea(parentLM, area);
+        return area;
+    }
+    
+    private void setupBasicLinkArea(LayoutManager parentLM,
+                                      InlineParent area) {
+         if (fobj.getExternalDestination() != null) {
+             area.addTrait(Trait.EXTERNAL_LINK, fobj.getExternalDestination());
+         } else {
+             String idref = fobj.getInternalDestination();
+             PageViewport page = getPSLM().getFirstPVWithID(idref);
+             if (page != null) {
+                 area.addTrait(Trait.INTERNAL_LINK, page.getKey());
+             } else {
+                 LinkResolver res = new LinkResolver(idref, area);
+                 getPSLM().addUnresolvedArea(idref, res);
+             }
+         }
+     }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/BidiLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/BidiLayoutManager.java
new file mode 100644 (file)
index 0000000..6a60f42
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.fo.flow.BidiOverride;
+
+
+/**
+ * If this bidi has a different writing mode direction
+ * ltr or rtl than its parent writing mode then this
+ * reverses the inline areas (at the character level).
+ */
+public class BidiLayoutManager extends LeafNodeLayoutManager {
+
+    private List children;
+
+    public BidiLayoutManager(BidiOverride node, InlineLayoutManager cLM) {
+        super(node);
+        children = new ArrayList();
+/*
+        for (int count = cLM.size() - 1; count >= 0; count--) {
+            InlineArea ia = cLM.get(count);
+            if (ia instanceof Word) {
+                // reverse word
+                Word word = (Word) ia;
+                StringBuffer sb = new StringBuffer(word.getWord());
+                word.setWord(sb.reverse().toString());
+            }
+            children.add(ia);
+        }
+*/
+    }
+
+    public int size() {
+        return children.size();
+    }
+
+    public InlineArea get(int index) {
+        return (InlineArea) children.get(index);
+    }
+
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
new file mode 100644 (file)
index 0000000..6d5a26f
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.fo.flow.Character;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager.AreaInfo;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.Trait;
+import org.apache.fop.traits.MinOptMax;
+import org.apache.fop.traits.SpaceVal;
+
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * LayoutManager for the fo:character formatting object
+ */
+public class CharacterLayoutManager extends LeafNodeLayoutManager {
+    private Character fobj;
+    private MinOptMax letterSpaceIPD;
+    private int hyphIPD;
+    private Font fs;
+
+    /**
+     * Constructor
+     *
+     * @param node the fo:character formatting object
+     * @todo better null checking of node
+     */
+    public CharacterLayoutManager(Character node) {
+        super(node);
+        fobj = node;
+        InlineArea inline = getCharacterInlineArea(node);
+        setCurrentArea(inline);
+        setAlignment(fobj.getVerticalAlign());
+        fs = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
+
+        SpaceVal ls = SpaceVal.makeLetterSpacing(fobj.getLetterSpacing());
+        letterSpaceIPD = ls.getSpace();
+        hyphIPD = fs.getCharWidth(fobj.getCommonHyphenation().hyphenationCharacter);
+    }
+
+    private InlineArea getCharacterInlineArea(Character node) {
+        org.apache.fop.area.inline.Character ch =
+            new org.apache.fop.area.inline.Character(node.getCharacter());
+        TraitSetter.addTextDecoration(ch, fobj.getTextDecoration());
+        return ch;
+    }
+
+    /**
+     * Offset this area.
+     * Offset the inline area in the bpd direction when adding the
+     * inline area.
+     * This is used for vertical alignment.
+     * Subclasses should override this if necessary.
+     * @param area the inline area to be updated
+     * @param context the layout context used for adding the area
+     */
+    protected void offsetArea(InlineArea area, LayoutContext context) {
+        int bpd = area.getBPD();
+        switch (verticalAlignment) {
+            case EN_MIDDLE:
+                area.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2);
+            break;
+            case EN_TOP:
+                area.setOffset(fs.getAscender());
+            break;
+            case EN_BOTTOM:
+                area.setOffset(context.getLineHeight() - bpd + fs.getAscender());
+            break;
+            case EN_BASELINE:
+            default:
+                area.setOffset(context.getBaseline());
+            break;
+        }
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        MinOptMax ipd;
+        curArea = get(context);
+        LinkedList returnList = new LinkedList();
+
+        if (curArea == null) {
+            setFinished(true);
+            return null;
+        }
+
+        ipd = new MinOptMax(fs.getCharWidth(((org.apache.fop.area.inline.Character) curArea).getChar().charAt(0)));
+
+        curArea.setIPD(ipd.opt);
+        curArea.setBPD(fs.getAscender() - fs.getDescender());
+
+        // offset is set in the offsetArea() method
+        //curArea.setOffset(textInfo.fs.getAscender());
+        //curArea.setOffset(context.getBaseline()); 
+
+        curArea.addTrait(Trait.FONT_NAME, fs.getFontName());
+        curArea.addTrait(Trait.FONT_SIZE, new Integer(fs.getFontSize()));
+        curArea.addTrait(Trait.COLOR, fobj.getColor());
+
+        int bpd = curArea.getBPD();
+        int lead = 0;
+        int total = 0;
+        int middle = 0;
+        switch (verticalAlignment) {
+            case EN_MIDDLE  : middle = bpd / 2 ;
+                                         break;
+            case EN_TOP     : // fall through
+            case EN_BOTTOM  : total = bpd;
+                                         break;
+            case EN_BASELINE: // fall through
+            default                    : lead = fs.getAscender();
+                                         total = bpd;
+                                         break;
+        }
+
+        // create the AreaInfo object to store the computed values
+        areaInfo = new AreaInfo((short) 0, ipd, false,
+                                lead, total, middle);
+
+        // node is a fo:Character
+        if (letterSpaceIPD.min == letterSpaceIPD.max) {
+            // constant letter space, only return a box
+            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+                                        areaInfo.total, areaInfo.middle,
+                                        new LeafPosition(this, 0), false));
+        } else {
+            // adjustable letter space, return a sequence of elements;
+            // at the moment the character is supposed to have no letter spaces,
+            // but returning this sequence allows us to change only one element
+            // if addALetterSpaceTo() is called
+            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+                                        areaInfo.total, areaInfo.middle,
+                                        new LeafPosition(this, 0), false));
+            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                            new LeafPosition(this, -1), true));
+            returnList.add(new KnuthGlue(0, 0, 0,
+                                         new LeafPosition(this, -1), true));
+            returnList.add(new KnuthInlineBox(0, 0, 0, 0,
+                                        new LeafPosition(this, -1), true));
+        }
+
+        setFinished(true);
+        return returnList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position bp) {
+        sbChars.append
+            (((org.apache.fop.area.inline.Character) curArea).getChar());
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        if (hc.getNextHyphPoint() == 1) {
+            // the character ends a syllable
+            areaInfo.bHyphenated = true;
+            bSomethingChanged = true;
+        } else {
+            // hc.getNextHyphPoint() returned -1 (no more hyphenation points)
+            // or a number > 1;
+            // the character does not end a syllable
+        }
+        hc.updateOffset(1);
+    }
+
+    public boolean applyChanges(List oldList) {
+        setFinished(false);
+        if (bSomethingChanged) {
+            // there is nothing to do,
+            // possible changes have already been applied
+            // in the hyphenate() method
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              int flaggedPenalty,
+                                              int alignment) {
+        if (isFinished()) {
+            return null;
+        }
+
+        LinkedList returnList = new LinkedList();
+
+        if (letterSpaceIPD.min == letterSpaceIPD.max
+            || areaInfo.iLScount == 0) {
+            // constant letter space, or no letter space
+            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+                                        areaInfo.total, areaInfo.middle,
+                                        new LeafPosition(this, 0), false));
+            if (areaInfo.bHyphenated) {
+                returnList.add
+                    (new KnuthPenalty(hyphIPD, flaggedPenalty, true,
+                                      new LeafPosition(this, -1), false));
+            }
+        } else {
+            // adjustable letter space
+            returnList.add
+                (new KnuthInlineBox(areaInfo.ipdArea.opt
+                              - areaInfo.iLScount * letterSpaceIPD.opt,
+                              areaInfo.lead, areaInfo.total, areaInfo.middle,
+                              new LeafPosition(this, 0), false));
+            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                            new LeafPosition(this, -1), true));
+            returnList.add
+                (new KnuthGlue(areaInfo.iLScount * letterSpaceIPD.opt,
+                               areaInfo.iLScount * letterSpaceIPD.max - letterSpaceIPD.opt,
+                               areaInfo.iLScount * letterSpaceIPD.opt - letterSpaceIPD.min,
+                               new LeafPosition(this, -1), true));
+            returnList.add(new KnuthInlineBox(0, 0, 0, 0,
+                                        new LeafPosition(this, -1), true));
+            if (areaInfo.bHyphenated) {
+                returnList.add
+                    (new KnuthPenalty(hyphIPD, flaggedPenalty, true,
+                                      new LeafPosition(this, -1), false));
+            }
+        }
+
+        setFinished(true);
+        return returnList;
+    }
+
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
new file mode 100644 (file)
index 0000000..d55208a
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.pagination.Title;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthPossPosIter;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.PageSequenceLayoutManager;
+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.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.ArrayList;
+import org.apache.fop.traits.MinOptMax;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Content Layout Manager.
+ * For use with objects that contain inline areas such as
+ * leader use-content and title.
+ */
+public class ContentLayoutManager implements InlineLevelLayoutManager {
+    private FOUserAgent userAgent;
+    private Area holder;
+    private int stackSize;
+    private LayoutManager parentLM;
+    private InlineLevelLayoutManager childLM = null;
+
+    /**
+     * logging instance
+     */
+    protected static Log log = LogFactory.getLog(LayoutManager.class);
+
+    /**
+     * Constructs a new ContentLayoutManager
+     *
+     * @param area  The parent area
+     */
+    public ContentLayoutManager(Area area, LayoutManager parentLM) {
+        holder = area;
+        this.parentLM = parentLM;
+    }
+
+    /**
+     * Constructor using a fo:title formatting object and its
+     * PageSequenceLayoutManager parent.
+     */
+    public ContentLayoutManager(Title foTitle, PageSequenceLayoutManager pslm) {
+        // get breaks then add areas to title
+        this.parentLM = pslm;
+        holder = new LineArea();
+
+        setUserAgent(foTitle.getUserAgent());
+
+        // use special layout manager to add the inline areas
+        // to the Title.
+        InlineLayoutManager lm;
+        lm = new InlineLayoutManager(foTitle);
+        addChildLM(lm);
+        fillArea(lm);
+    }
+
+    public void fillArea(LayoutManager curLM) {
+
+        int ipd = 1000000;
+
+        LayoutContext childLC = new LayoutContext(LayoutContext.NEW_AREA);
+        childLC.setLeadingSpace(new SpaceSpecifier(false));
+        childLC.setTrailingSpace(new SpaceSpecifier(false));
+        // set stackLimit for lines
+        childLC.setStackLimit(new MinOptMax(ipd));
+        childLC.setRefIPD(ipd);
+
+        int lineHeight = 14000;
+        int lead = 12000;
+        int follow = 2000;
+
+        int halfLeading = (lineHeight - lead - follow) / 2;
+        // height before baseline
+        int lineLead = lead + halfLeading;
+        // maximum size of top and bottom alignment
+        int maxtb = follow + halfLeading;
+        // max size of middle alignment below baseline
+        int middlefollow = maxtb;
+
+        stackSize = 0;
+
+        LinkedList contentList =
+            getNextKnuthElements(childLC, Constants.EN_START);
+        ListIterator contentIter = contentList.listIterator();
+        while (contentIter.hasNext()) {
+            KnuthElement element = (KnuthElement) contentIter.next();
+            if (element.isBox()) {
+                KnuthInlineBox box = (KnuthInlineBox) element;
+                if (box.getLead() > lineLead) {
+                    lineLead = box.getLead();
+                }
+                if (box.getTotal() > maxtb) {
+                    maxtb = box.getTotal();
+                }
+                // Is this needed? cf. LineLM.makeLineBreakPosition
+                // if (box.getMiddle() > lineLead) {
+                //     lineLead = box.getMiddle();
+                // }
+                if (box.getMiddle() > middlefollow) {
+                    middlefollow = box.getMiddle();
+                }
+            }
+        }
+
+        if (maxtb - lineLead > middlefollow) {
+            middlefollow = maxtb - lineLead;
+        }
+
+        LayoutContext lc = new LayoutContext(0);
+        lc.setBaseline(lineLead);
+        lc.setLineHeight(lineHeight);
+
+        lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+        lc.setLeadingSpace(new SpaceSpecifier(false));
+        lc.setTrailingSpace(new SpaceSpecifier(false));
+        KnuthPossPosIter contentPosIter =
+            new KnuthPossPosIter(contentList, 0, contentList.size());
+        curLM.addAreas(contentPosIter, lc);
+    }
+
+    public void addAreas(PositionIterator posIter, LayoutContext context) {
+        // add the content areas
+        // the area width has already been adjusted, and it must remain unchanged
+        // so save its value before calling addAreas, and set it again afterwards
+        int savedIPD = ((InlineArea)holder).getIPD();
+        // set to zero the ipd adjustment ratio, to avoid spaces in the pattern
+        // to be modified
+        LayoutContext childContext = new LayoutContext(context);
+        childContext.setIPDAdjust(0.0);
+        childLM.addAreas(posIter, childContext);
+        ((InlineArea)holder).setIPD(savedIPD);
+    }
+
+    public int getStackingSize() {
+        return stackSize;
+    }
+
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
+    public Area getParentArea(Area childArea) {
+        return holder;
+    }
+
+    /** 
+     * @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
+     **/
+    public void addChildArea(Area childArea) {
+        holder.addChildArea(childArea);
+    }
+
+    /**
+     * Set the user agent.
+     *
+     * @param ua the user agent
+     */
+    public void setUserAgent(FOUserAgent ua) {
+        userAgent = ua;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getUserAgent()
+     */
+    public FOUserAgent getUserAgent() {
+        return userAgent;
+    }
+
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
+    public void setParent(LayoutManager lm) {
+        parentLM = lm;
+    }
+
+    public LayoutManager getParent() {
+        return this.parentLM;
+    }
+
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
+    public boolean isFinished() {
+        return false;
+    }
+
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
+    public void setFinished(boolean isFinished) {
+        //to be done
+    }
+
+    /** @see org.apache.fop.layoutmgr.LayoutManager */
+    public void resetPosition(Position position) {
+        //to be done
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#createNextChildLMs
+     */
+    public boolean createNextChildLMs(int pos) {
+        return false;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#getChildLMs
+     */
+    public List getChildLMs() {
+        List childLMs = new ArrayList(1);
+        childLMs.add(childLM);
+        return childLMs;
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#addChildLM
+     */
+    public void addChildLM(LayoutManager lm) {
+        if (lm == null) {
+            return;
+        }
+        lm.setParent(this);
+        childLM = (InlineLevelLayoutManager)lm;
+        log.trace(this.getClass().getName()
+                  + ": Adding child LM " + lm.getClass().getName());
+    }
+
+    /**
+     * @see org.apache.fop.layoutmgr.LayoutManager#addChildLMs
+     */
+    public void addChildLMs(List newLMs) {
+        if (newLMs == null || newLMs.size() == 0) {
+            return;
+        }
+        ListIterator iter = newLMs.listIterator();
+        while (iter.hasNext()) {
+            LayoutManager lm = (LayoutManager) iter.next();
+            addChildLM(lm);
+        }
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        LinkedList contentList = new LinkedList();
+        LinkedList returnedList;
+
+        while (!childLM.isFinished()) {
+            // get KnuthElements from childLM
+            returnedList = childLM.getNextKnuthElements(context, alignment);
+
+            if (returnedList != null) {
+                // move elements to contentList, and accumulate their size
+               KnuthElement contentElement;
+               while (returnedList.size() > 0) {
+                    contentElement = (KnuthElement)returnedList.removeFirst();
+                    stackSize += contentElement.getW();
+                    contentList.add(contentElement);
+                }
+            }
+        }
+
+        setFinished(true);
+        return contentList;
+    }
+
+    public List addALetterSpaceTo(List oldList) {
+        return oldList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+    }
+
+    public boolean applyChanges(List oldList) {
+        return false;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              /*int flaggedPenalty,*/
+                                              int alignment) {
+        return null;
+    }
+    
+    public PageSequenceLayoutManager getPSLM() {
+        return parentLM.getPSLM();
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java
new file mode 100644 (file)
index 0000000..a0196f8
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+// Java
+import java.awt.geom.Rectangle2D;
+
+// FOP
+import org.apache.fop.area.inline.Image;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.Viewport;
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.fo.flow.ExternalGraphic;
+import org.apache.fop.layoutmgr.TraitSetter;
+
+/**
+ * LayoutManager for the fo:external-graphic formatting object
+ */
+public class ExternalGraphicLayoutManager extends LeafNodeLayoutManager {
+    
+    private ExternalGraphic fobj;
+
+    private int breakAfter;
+    private int breakBefore;
+    private int align;
+    private int startIndent;
+    private int endIndent;
+    private int spaceBefore;
+    private int spaceAfter;
+    private int viewWidth = -1;
+    private int viewHeight = -1;
+    private boolean clip = false;
+    private Rectangle2D placement = null;
+
+    /**
+     * Constructor
+     *
+     * @param node the fo:external-graphic formatting object that creates the area
+     */
+    public ExternalGraphicLayoutManager(ExternalGraphic node) {
+        super(node);
+        fobj = node;
+        setup();
+        InlineArea area = getExternalGraphicInlineArea();
+        setCurrentArea(area);
+        setAlignment(fobj.getVerticalAlign());
+        setLead(viewHeight);
+    }
+
+    /**
+     * Setup this image.
+     * This gets the sizes for the image and the dimensions and clipping.
+     * @todo see if can simplify property handling logic
+     */
+    private void setup() {
+        // assume lr-tb for now and just use the .optimum value of the range
+        Length ipd = fobj.getInlineProgressionDimension().getOptimum().getLength();
+        if (ipd.getEnum() != EN_AUTO) {
+            viewWidth = ipd.getValue();
+        } else {
+            ipd = fobj.getWidth();
+            if (ipd.getEnum() != EN_AUTO) {
+                viewWidth = ipd.getValue();
+            }
+        }
+        Length bpd = fobj.getBlockProgressionDimension().getOptimum().getLength();
+        if (bpd.getEnum() != EN_AUTO) {
+            viewHeight = bpd.getValue();
+        } else {
+            bpd = fobj.getHeight();
+            if (bpd.getEnum() != EN_AUTO) {
+                viewHeight = bpd.getValue();
+            }
+        }
+
+        int cwidth = -1;
+        int cheight = -1;
+        Length ch = fobj.getContentHeight();
+        if (ch.getEnum() != EN_AUTO) {
+            if (ch.getEnum() == EN_SCALE_TO_FIT) {
+                if (viewHeight != -1) {
+                    cheight = viewHeight;
+                }
+            } else {
+                cheight = ch.getValue();
+            }
+        }
+        Length cw = fobj.getContentWidth();
+        if (cw.getEnum() != EN_AUTO) {
+            if (cw.getEnum() == EN_SCALE_TO_FIT) {
+                if (viewWidth != -1) {
+                    cwidth = viewWidth;
+                }
+            } else {
+                cwidth = cw.getValue();
+            }
+        }
+
+        int scaling = fobj.getScaling();
+        if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
+            if (cwidth == -1 && cheight == -1) {
+                cwidth = fobj.getIntrinsicWidth();
+                cheight = fobj.getIntrinsicHeight();
+            } else if (cwidth == -1) {
+                cwidth = (int)(fobj.getIntrinsicWidth() * (double)cheight 
+                    / fobj.getIntrinsicHeight());
+            } else if (cheight == -1) {
+                cheight = (int)(fobj.getIntrinsicHeight() * (double)cwidth 
+                    / fobj.getIntrinsicWidth());
+            } else {
+                // adjust the larger
+                double rat1 = cwidth / fobj.getIntrinsicWidth();
+                double rat2 = cheight / fobj.getIntrinsicHeight();
+                if (rat1 < rat2) {
+                    // reduce cheight
+                    cheight = (int)(rat1 * fobj.getIntrinsicHeight());
+                } else if (rat1 > rat2) {
+                    cwidth = (int)(rat2 * fobj.getIntrinsicWidth());
+                }
+            }
+        }
+
+        if (viewWidth == -1) {
+            viewWidth = cwidth;
+        }
+        if (viewHeight == -1) {
+            viewHeight = cheight;
+        }
+
+        if (cwidth > viewWidth || cheight > viewHeight) {
+            int overflow = fobj.getOverflow();
+            if (overflow == EN_HIDDEN) {
+                clip = true;
+            } else if (overflow == EN_ERROR_IF_OVERFLOW) {
+                fobj.getLogger().error("Image: " + fobj.getURL()
+                                  + " overflows the viewport, clipping to viewport");
+                clip = true;
+            }
+        }
+
+        int xoffset = 0;
+        int yoffset = 0;
+        switch(fobj.getDisplayAlign()) {
+            case EN_BEFORE:
+            break;
+            case EN_AFTER:
+                yoffset = viewHeight - cheight;
+            break;
+            case EN_CENTER:
+                yoffset = (viewHeight - cheight) / 2;
+            break;
+            case EN_AUTO:
+            default:
+            break;
+        }
+
+        switch(fobj.getTextAlign()) {
+            case EN_CENTER:
+                xoffset = (viewWidth - cwidth) / 2;
+            break;
+            case EN_END:
+                xoffset = viewWidth - cwidth;
+            break;
+            case EN_START:
+            break;
+            case EN_JUSTIFY:
+            default:
+            break;
+        }
+        placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
+    }
+
+     /**
+      * Get the inline area for this external grpahic.
+      * This creates the image area and puts it inside a viewport.
+      *
+      * @return the viewport containing the image area
+      */
+     public InlineArea getExternalGraphicInlineArea() {
+         Image imArea = new Image(fobj.getSrc());
+         Viewport vp = new Viewport(imArea);
+         vp.setIPD(viewWidth);
+         vp.setBPD(viewHeight);
+         vp.setClip(clip);
+         vp.setContentPosition(placement);
+         vp.setOffset(0);
+
+         // Common Border, Padding, and Background Properties
+         TraitSetter.addBorders(vp, fobj.getCommonBorderPaddingBackground());
+         TraitSetter.addBackground(vp, fobj.getCommonBorderPaddingBackground());
+
+         return vp;
+     }
+     
+     protected void addId() {
+         getPSLM().addIDToPage(fobj.getId());
+     }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/FootnoteLayoutManager.java
new file mode 100644 (file)
index 0000000..e39292f
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+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.LayoutContext;
+import org.apache.fop.layoutmgr.Position;
+
+public class FootnoteLayoutManager extends AbstractLayoutManager 
+                                   implements InlineLevelLayoutManager {
+
+    private Footnote footnote;
+    private InlineStackingLayoutManager citationLM;
+    private FootnoteBodyLayoutManager bodyLM;
+
+    /**
+     * Create a new footnote layout manager.
+     * @param node footnote to create the layout manager for
+     */
+    public FootnoteLayoutManager(Footnote node) {
+        super(node);
+        footnote = node;
+
+        // create an InlineStackingLM handling the fo:inline child of fo:footnote
+        citationLM = new InlineStackingLayoutManager(footnote.getFootnoteCitation());
+
+        // create a FootnoteBodyLM handling the fo:footnote-body child of fo:footnote
+        bodyLM = new FootnoteBodyLayoutManager(footnote.getFootnoteBody());
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        // this is the only method that must be implemented:
+        // all other methods will never be called, as the returned elements
+        // contain Positions created by the citationLM, so its methods will
+        // be called instead
+
+        // set the citationLM parent to be this LM's parent
+        citationLM.setParent(getParent());
+        bodyLM.setParent(this);
+
+        // get Knuth elements representing the footnote citation
+        LinkedList returnedList = new LinkedList();
+        while (!citationLM.isFinished()) {
+            LinkedList partialList = citationLM.getNextKnuthElements(context, alignment);
+            if (partialList != null) {
+                returnedList.addAll(partialList);
+            }
+        }
+        if (returnedList.size() == 0) {
+            //Inline part of the footnote is empty. Need to send back an auxiliary
+            //zero-width, zero-height inline box so the footnote gets painted.
+            returnedList.add(new KnuthInlineBox(0, 0, 0, 0, null, true));
+        }
+        setFinished(true);
+
+        addAnchor(returnedList);
+
+        return returnedList;
+    }
+
+    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;
+        while (citationIterator.hasPrevious() && lastBox == null) {
+            KnuthElement element = (KnuthElement) citationIterator.previous();
+            if (element instanceof KnuthInlineBox) {
+                lastBox = (KnuthInlineBox) element;
+            }
+        }
+        if (lastBox != null) {
+            lastBox.setFootnoteBodyLM(bodyLM);
+        }
+    }
+
+    public List addALetterSpaceTo(List oldList) {
+        log.warn("null implementation of addALetterSpaceTo() called!");
+        return oldList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+        log.warn("null implementation of getWordChars() called!");
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        log.warn("null implementation of hyphenate called!");
+    }
+
+    public boolean applyChanges(List oldList) {
+        log.warn("null implementation of applyChanges() called!");
+        return false;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              int alignment) {
+        log.warn("null implementation of getChangeKnuthElement() called!");
+        return null;
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/HyphContext.java b/src/java/org/apache/fop/layoutmgr/inline/HyphContext.java
new file mode 100644 (file)
index 0000000..86e8ba4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+/**
+ * This class is used to pass information to the getNextBreakPoss()
+ * method concerning hyphenation. A reference to an instance of the
+ * class is contained in the LayoutContext object passed to each
+ * LayoutManager. It contains information concerning the hyphenation
+ * points in a word and the how many of those have previously been
+ * processed by a Layout Manager to generate size information.
+ */
+public class HyphContext {
+    private int[] hyphPoints;
+    private int currentOffset = 0;
+    private int currentIndex = 0;
+
+    public HyphContext(int[] hyphPoints) {
+        this.hyphPoints = hyphPoints;
+    }
+
+    public int getNextHyphPoint() {
+        for (; currentIndex < hyphPoints.length; currentIndex++) {
+            if (hyphPoints[currentIndex] > currentOffset) {
+                return (hyphPoints[currentIndex] - currentOffset);
+            }
+        }
+        return -1; // AT END!
+    }
+
+    public boolean hasMoreHyphPoints() {
+        for (; currentIndex < hyphPoints.length; currentIndex++) {
+            if (hyphPoints[currentIndex] > currentOffset) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void updateOffset(int iCharsProcessed) {
+        currentOffset += iCharsProcessed;
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ICLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ICLayoutManager.java
new file mode 100644 (file)
index 0000000..87ce904
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+// Java
+import java.util.List;
+
+// FOP
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.fo.flow.InlineContainer;
+/**
+ * This creates a single inline container area after
+ * laying out the child block areas. All footnotes, floats
+ * and id areas are maintained for later retrieval.
+ */
+public class ICLayoutManager extends LeafNodeLayoutManager {
+    private InlineContainer fobj;
+    private List childrenLM;
+
+    public ICLayoutManager(InlineContainer node, List childLM) {
+        super(node);
+        fobj = node;
+        childrenLM = childLM;
+    }
+
+    public InlineArea get(int index) {
+        return null;
+    }
+
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
new file mode 100755 (executable)
index 0000000..76222cf
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+import java.util.ListIterator;
+import java.util.LinkedList;
+
+import org.apache.fop.fo.flow.InlineLevel;
+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.LayoutContext;
+import org.apache.fop.layoutmgr.NonLeafPosition;
+import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.traits.MinOptMax;
+import org.apache.fop.traits.SpaceVal;
+
+/**
+ * LayoutManager for objects which stack children in the inline direction,
+ * such as Inline or Line
+ */
+public class InlineLayoutManager extends InlineStackingLayoutManager 
+                                         implements InlineLevelLayoutManager {
+    private InlineLevel fobj;
+
+    private CommonMarginInline inlineProps = null;
+    private CommonBorderPaddingBackground borderProps = null;
+
+    /**
+     * Create an inline layout manager.
+     * This is used for fo's that create areas that
+     * contain inline areas.
+     *
+     * @param node the formatting object that creates the area
+     */
+    // The node should be FObjMixed
+    public InlineLayoutManager(InlineLevel node) {
+        super(node);
+        fobj = node;
+        initialize();
+    }
+    
+    private void initialize() {
+        inlineProps = fobj.getCommonMarginInline();
+        borderProps = fobj.getCommonBorderPaddingBackground();
+
+        int iPad = borderProps.getPadding(CommonBorderPaddingBackground.BEFORE, false);
+        iPad += borderProps.getBorderWidth(CommonBorderPaddingBackground.BEFORE,
+                                             false);
+        iPad += borderProps.getPadding(CommonBorderPaddingBackground.AFTER, false);
+        iPad += borderProps.getBorderWidth(CommonBorderPaddingBackground.AFTER, false);
+        extraBPD = new MinOptMax(iPad);
+    }
+
+    protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
+        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.START,
+                                           bNotFirst);
+        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.START,
+                                            bNotFirst);
+        iBP += borderProps.getPadding(CommonBorderPaddingBackground.END, bNotLast);
+        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, bNotLast);
+        return new MinOptMax(iBP);
+    }
+
+
+    protected boolean hasLeadingFence(boolean bNotFirst) {
+        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.START,
+                                           bNotFirst);
+        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.START,
+                                            bNotFirst);
+        return (iBP > 0);
+    }
+
+    protected boolean hasTrailingFence(boolean bNotLast) {
+        int iBP = borderProps.getPadding(CommonBorderPaddingBackground.END, bNotLast);
+        iBP += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, bNotLast);
+        return (iBP > 0);
+    }
+
+    protected SpaceProperty getSpaceStart() {
+        return inlineProps.spaceStart;
+    }
+    protected SpaceProperty getSpaceEnd() {
+        return inlineProps.spaceEnd;
+    }
+    
+    protected void setTraits(boolean bNotFirst, boolean bNotLast) {
+        
+        // Add border and padding to current area and set flags (FIRST, LAST ...)
+        TraitSetter.setBorderPaddingTraits(getCurrentArea(),
+                                           borderProps, bNotFirst, bNotLast);
+
+        if (borderProps != null) {
+            TraitSetter.addBorders(getCurrentArea(), borderProps);
+            TraitSetter.addBackground(getCurrentArea(), borderProps);
+        }
+    }
+
+    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);
+            if (getSpaceStart() != null) {
+                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);
+                }
+                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 KnuthElement addALetterSpaceTo(KnuthElement element) {
+        NonLeafPosition savedPos = (NonLeafPosition) element.getPosition();
+        element.setPosition(savedPos.getPosition());
+
+        KnuthElement newElement
+            = ((InlineLevelLayoutManager)
+               element.getLayoutManager()).addALetterSpaceTo(element);
+        newElement.setPosition
+            (new NonLeafPosition(this, newElement.getPosition()));
+        element.setPosition(savedPos);
+        return newElement;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+        Position newPos = ((NonLeafPosition) pos).getPosition();
+        ((InlineLevelLayoutManager)
+         newPos.getLM()).getWordChars(sbChars, newPos);
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        Position newPos = ((NonLeafPosition) pos).getPosition();
+        ((InlineLevelLayoutManager)
+         newPos.getLM()).hyphenate(newPos, hc);
+    }
+
+    public boolean applyChanges(List oldList) {
+        // "unwrap" the Positions stored in the elements
+        ListIterator oldListIterator = oldList.listIterator();
+        KnuthElement oldElement;
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (((NonLeafPosition) oldElement.getPosition()).getPosition());
+        }
+        // reset the iterator
+        oldListIterator = oldList.listIterator();
+
+        InlineLevelLayoutManager prevLM = null;
+        InlineLevelLayoutManager currLM;
+        int fromIndex = 0;
+
+        boolean bSomethingChanged = false;
+        while(oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
+            // initialize prevLM
+            if (prevLM == null) {
+                prevLM = currLM;
+            }
+
+            if (currLM != prevLM || !oldListIterator.hasNext()) {
+                if (oldListIterator.hasNext()) {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
+                        || bSomethingChanged;
+                    prevLM = currLM;
+                    fromIndex = oldListIterator.previousIndex();
+                } else if (currLM == prevLM) {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldList.size()))
+                        || bSomethingChanged;
+                } else {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
+                        || bSomethingChanged;
+                    bSomethingChanged
+                        = currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size()))
+                        || bSomethingChanged;
+                }
+            }
+        }
+
+        // "wrap" again the Positions stored in the elements
+        oldListIterator = oldList.listIterator();
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (new NonLeafPosition(this, oldElement.getPosition()));
+        }
+        return bSomethingChanged;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList, int flaggedPenalty, int alignment) {
+        // "unwrap" the Positions stored in the elements
+        ListIterator oldListIterator = oldList.listIterator();
+        KnuthElement oldElement;
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (((NonLeafPosition) oldElement.getPosition()).getPosition());
+        }
+        // reset the iterator
+        oldListIterator = oldList.listIterator();
+
+        KnuthElement returnedElement;
+        LinkedList returnedList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        InlineLevelLayoutManager prevLM = null;
+        InlineLevelLayoutManager currLM;
+        int fromIndex = 0;
+
+        while(oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
+            if (prevLM == null) {
+                prevLM = currLM;
+            }
+
+            if (currLM != prevLM || !oldListIterator.hasNext()) {
+                if (oldListIterator.hasNext()) {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex,
+                                          oldListIterator.previousIndex()),
+                          flaggedPenalty, alignment));
+                    prevLM = currLM;
+                    fromIndex = oldListIterator.previousIndex();
+                } else if (currLM == prevLM) {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex, oldList.size()),
+                          flaggedPenalty, alignment));
+                } else {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex,
+                                          oldListIterator.previousIndex()),
+                          flaggedPenalty, alignment));
+                    returnedList.addAll
+                        (currLM.getChangedKnuthElements
+                         (oldList.subList(oldListIterator.previousIndex(),
+                                          oldList.size()),
+                          flaggedPenalty, alignment));
+                }
+            }
+        }
+
+        // "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);
+        }
+        return returnList;
+    }*/
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLevelLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLevelLayoutManager.java
new file mode 100644 (file)
index 0000000..71c6adc
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2004-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.layoutmgr.inline;
+
+import java.util.List;
+
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.Position;
+
+/**
+ * The interface for LayoutManagers which generate inline areas
+ */
+public interface InlineLevelLayoutManager extends LayoutManager {
+
+    /**
+     * Tell the LM to modify its data, adding a letter space 
+     * to the word fragment represented by the given elements,
+     * and returning the corrected elements
+     *
+     * @param oldList the elements which must be given one more letter space
+     * @return        the new elements replacing the old ones
+     */
+    List addALetterSpaceTo(List oldList);
+
+    /**
+     * Get the word chars corresponding to the given position
+     *
+     * @param sbChars the StringBuffer used to append word chars
+     * @param pos     the Position referring to the needed word chars
+     */
+    void getWordChars(StringBuffer sbChars, Position pos);
+
+    /**
+     * Tell the LM to hyphenate a word
+     *
+     * @param pos the Position referring to the word
+     * @param hc  the HyphContext storing hyphenation information
+     */
+    void hyphenate(Position pos, HyphContext hc);
+
+    /**
+     * Tell the LM to apply the changes due to hyphenation
+     *
+     * @param oldList the list of the old elements the changes refer to
+     * @return        true if the LM had to change its data, false otherwise
+     */
+    boolean applyChanges(List oldList);
+
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
new file mode 100644 (file)
index 0000000..28be052
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.HashMap;
+
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.properties.SpaceProperty;
+import org.apache.fop.layoutmgr.AbstractLayoutManager;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.LayoutContext;
+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;
+
+/**
+ * Class modelling the commonalities of layoutmanagers for objects
+ * which stack children in the inline direction, such as Inline or
+ * Line. It should not be instantiated directly.
+ */
+public class InlineStackingLayoutManager extends AbstractLayoutManager 
+                                         implements InlineLevelLayoutManager {
+
+
+    private static class StackingIter extends PositionIterator {
+
+        StackingIter(Iterator parentIter) {
+            super(parentIter);
+        }
+
+        protected LayoutManager getLM(Object nextObj) {
+            return ((Position) nextObj).getLM();
+        }
+
+        protected Position getPos(Object nextObj) {
+            return ((Position) nextObj);
+        }
+    }
+
+
+    /**
+     * Size of any start or end borders and padding.
+     */
+    private MinOptMax allocIPD = new MinOptMax(0);
+
+    /**
+     * Size of border and padding in BPD (ie, before and after).
+     */
+    protected MinOptMax extraBPD;
+
+    private Area currentArea; // LineArea or InlineParent
+
+    //private BreakPoss prevBP;
+    protected LayoutContext childLC;
+
+    private LayoutManager lastChildLM = null; // Set when return last breakposs
+    private boolean bAreaCreated = false;
+
+    //private LayoutManager currentLM = null;
+
+    /** Used to store previous content IPD for each child LM. */
+    private HashMap hmPrevIPD = new HashMap();
+
+    /**
+     * Create an inline stacking layout manager.
+     * This is used for fo's that create areas that
+     * contain inline areas.
+     *
+     * @param node the formatting object that creates the area
+     */
+    protected InlineStackingLayoutManager(FObj node) {
+        super(node);
+        extraBPD = new MinOptMax(0);
+    }
+
+    /**
+     * Set the iterator.
+     *
+     * @param iter the iterator for this LM
+     */
+    public void setLMiter(ListIterator iter) {
+        childLMiter = iter;
+    }
+
+    protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
+        return new MinOptMax(0);
+    }
+
+
+    protected boolean hasLeadingFence(boolean bNotFirst) {
+        return false;
+    }
+
+    protected boolean hasTrailingFence(boolean bNotLast) {
+        return false;
+    }
+
+    protected SpaceProperty getSpaceStart() {
+        return null;
+    }
+    
+    protected SpaceProperty getSpaceEnd() {
+        return null;
+    }
+
+    /**
+     * Reset position for returning next BreakPossibility.
+     * @param prevPos a Position returned by this layout manager
+     * representing a potential break decision.
+     */
+    public void resetPosition(Position prevPos) {
+        if (prevPos != null) {
+            // ASSERT (prevPos.getLM() == this)
+            if (prevPos.getLM() != this) {
+                //getLogger().error(
+                //  "InlineStackingLayoutManager.resetPosition: " +
+                //  "LM mismatch!!!");
+            }
+            // Back up the child LM Position
+            Position childPos = prevPos.getPosition();
+            reset(childPos);
+            /*
+            if (prevBP != null
+                    && prevBP.getLayoutManager() != childPos.getLM()) {
+                childLC = null;
+            }
+            prevBP = new BreakPoss(childPos);
+            */
+        } else {
+            // Backup to start of first child layout manager
+            //prevBP = null;
+            // super.resetPosition(prevPos);
+            reset(prevPos);
+            // If any areas created, we are restarting!
+            bAreaCreated = false;
+        }
+        // Do we need to reset some context like pending or prevContent?
+        // What about prevBP?
+    }
+
+    protected MinOptMax getPrevIPD(LayoutManager lm) {
+        return (MinOptMax) hmPrevIPD.get(lm);
+    }
+
+    /**
+     * Clear the previous IPD calculation.
+     */
+    protected void clearPrevIPD() {
+        hmPrevIPD.clear();
+    }
+
+    protected InlineParent createArea() {
+        return new InlineParent();
+    }
+
+    /**
+     * 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) {
+        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;
+    }
+
+    protected void setCurrentArea(Area area) {
+        currentArea = area;
+    }
+
+    protected void setTraits(boolean bNotFirst, boolean bNotLast) {
+        
+    }
+
+    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;
+    }
+
+    // Current child layout context
+    protected LayoutContext getContext() {
+        return childLC;
+    }
+
+    protected void addSpace(Area parentArea, MinOptMax spaceRange,
+                            double dSpaceAdjust) {
+        if (spaceRange != null) {
+            int iAdjust = spaceRange.opt;
+            if (dSpaceAdjust > 0.0) {
+                // Stretch by factor
+                iAdjust += (int) ((double) (spaceRange.max
+                                          - spaceRange.opt) * dSpaceAdjust);
+            } else if (dSpaceAdjust < 0.0) {
+                // Shrink by factor
+                iAdjust += (int) ((double) (spaceRange.opt
+                                          - spaceRange.min) * dSpaceAdjust);
+            }
+            if (iAdjust != 0) {
+                //getLogger().debug("Add leading space: " + iAdjust);
+                Space ls = new Space();
+                ls.setIPD(iAdjust);
+                parentArea.addChildArea(ls);
+            }
+        }
+    }
+
+    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
+
+        ListIterator oldListIterator = oldList.listIterator();
+        KnuthElement element = null;
+        // "unwrap" the Position stored in each element of oldList
+        while (oldListIterator.hasNext()) {
+            element = (KnuthElement) oldListIterator.next();
+            element.setPosition(((NonLeafPosition)element.getPosition()).getPosition());
+        }
+
+        oldList = ((InlineLevelLayoutManager)
+                   element.getLayoutManager()).addALetterSpaceTo(oldList);
+
+        // "wrap" againg the Position stored in each element of oldList
+        oldListIterator = oldList.listIterator();
+        while (oldListIterator.hasNext()) {
+            element = (KnuthElement) oldListIterator.next();
+            element.setPosition(new NonLeafPosition(this, element.getPosition()));
+        }
+
+        return oldList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+        Position newPos = ((NonLeafPosition) pos).getPosition();
+        ((InlineLevelLayoutManager)
+         newPos.getLM()).getWordChars(sbChars, newPos);
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        Position newPos = ((NonLeafPosition) pos).getPosition();
+        ((InlineLevelLayoutManager)
+         newPos.getLM()).hyphenate(newPos, hc);
+    }
+
+    public boolean applyChanges(List oldList) {
+        // "unwrap" the Positions stored in the elements
+        ListIterator oldListIterator = oldList.listIterator();
+        KnuthElement oldElement;
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (((NonLeafPosition) oldElement.getPosition()).getPosition());
+        }
+        // reset the iterator
+        oldListIterator = oldList.listIterator();
+
+        InlineLevelLayoutManager prevLM = null;
+        InlineLevelLayoutManager currLM;
+        int fromIndex = 0;
+
+        boolean bSomethingChanged = false;
+        while(oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
+            // initialize prevLM
+            if (prevLM == null) {
+                prevLM = currLM;
+            }
+
+            if (currLM != prevLM || !oldListIterator.hasNext()) {
+                if (oldListIterator.hasNext()) {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
+                        || bSomethingChanged;
+                    prevLM = currLM;
+                    fromIndex = oldListIterator.previousIndex();
+                } else if (currLM == prevLM) {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldList.size()))
+                        || bSomethingChanged;
+                } else {
+                    bSomethingChanged
+                        = prevLM.applyChanges(oldList.subList(fromIndex, oldListIterator.previousIndex()))
+                        || bSomethingChanged;
+                    bSomethingChanged
+                        = currLM.applyChanges(oldList.subList(oldListIterator.previousIndex(), oldList.size()))
+                        || bSomethingChanged;
+                }
+            }
+        }
+
+        // "wrap" again the Positions stored in the elements
+        oldListIterator = oldList.listIterator();
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (new NonLeafPosition(this, oldElement.getPosition()));
+        }
+        return bSomethingChanged;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList, /*int flaggedPenalty,*/ int alignment) {
+        // "unwrap" the Positions stored in the elements
+        ListIterator oldListIterator = oldList.listIterator();
+        KnuthElement oldElement;
+        while (oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            oldElement.setPosition
+                (((NonLeafPosition) oldElement.getPosition()).getPosition());
+        }
+        // reset the iterator
+        oldListIterator = oldList.listIterator();
+
+        KnuthElement returnedElement;
+        LinkedList returnedList = new LinkedList();
+        LinkedList returnList = new LinkedList();
+        InlineLevelLayoutManager prevLM = null;
+        InlineLevelLayoutManager currLM;
+        int fromIndex = 0;
+
+        while(oldListIterator.hasNext()) {
+            oldElement = (KnuthElement) oldListIterator.next();
+            currLM = (InlineLevelLayoutManager) oldElement.getLayoutManager();
+            if (prevLM == null) {
+                prevLM = currLM;
+            }
+
+            if (currLM != prevLM || !oldListIterator.hasNext()) {
+                if (oldListIterator.hasNext()) {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex,
+                                          oldListIterator.previousIndex()),
+                          /*flaggedPenalty,*/ alignment));
+                    prevLM = currLM;
+                    fromIndex = oldListIterator.previousIndex();
+                } else if (currLM == prevLM) {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex, oldList.size()),
+                          /*flaggedPenalty,*/ alignment));
+                } else {
+                    returnedList.addAll
+                        (prevLM.getChangedKnuthElements
+                         (oldList.subList(fromIndex,
+                                          oldListIterator.previousIndex()),
+                          /*flaggedPenalty,*/ alignment));
+                    returnedList.addAll
+                        (currLM.getChangedKnuthElements
+                         (oldList.subList(oldListIterator.previousIndex(),
+                                          oldList.size()),
+                          /*flaggedPenalty,*/ alignment));
+                }
+            }
+        }
+
+        // "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);
+        }
+        return returnList;
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java b/src/java/org/apache/fop/layoutmgr/inline/InstreamForeignObjectLM.java
new file mode 100644 (file)
index 0000000..3b88ac0
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright 1999-2004 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.layoutmgr.inline;
+
+// Java
+import java.awt.geom.Rectangle2D;
+
+// FOP
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.fo.XMLObj;
+import org.apache.fop.fo.flow.InstreamForeignObject;
+import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.area.inline.ForeignObject;
+import org.apache.fop.area.inline.Viewport;
+
+/**
+ * LayoutManager for the fo:instream-foreign-object formatting object
+ */
+public class InstreamForeignObjectLM extends LeafNodeLayoutManager {
+    
+    private InstreamForeignObject fobj;
+    
+    /**
+     * Constructor
+     * @param node the formatting object that creates this area
+     */
+    public InstreamForeignObjectLM(InstreamForeignObject node) {
+        super(node);
+        fobj = node;
+        Viewport areaCurrent = getInlineArea();
+        setCurrentArea(areaCurrent);
+        setAlignment(node.getVerticalAlign());
+        setLead(areaCurrent.getBPD());
+    }
+
+    /**
+     * Get the inline area created by this element.
+     *
+     * @return the viewport inline area
+     */
+    private Viewport getInlineArea() {
+        XMLObj child = (XMLObj) fobj.childNodes.get(0);
+
+        // viewport size is determined by block-progression-dimension
+        // and inline-progression-dimension
+
+        // if replaced then use height then ignore block-progression-dimension
+        //int h = this.propertyList.get("height").getLength().mvalue();
+
+        // use specified line-height then ignore dimension in height direction
+        boolean hasLH = false; //propertyList.get("line-height").getSpecifiedValue() != null;
+
+        Length len;
+
+        int bpd = -1;
+        int ipd = -1;
+        boolean bpdauto = false;
+        if (hasLH) {
+            bpd = fobj.getLineHeight().getValue();
+        } else {
+            // this property does not apply when the line-height applies
+            // isn't the block-progression-dimension always in the same
+            // direction as the line height?
+            len = fobj.getBlockProgressionDimension().getOptimum().getLength();
+            if (len.getEnum() != EN_AUTO) {
+                bpd = len.getValue();
+            } else {
+                len = fobj.getHeight();
+                if (len.getEnum() != EN_AUTO) {
+                    bpd = len.getValue();
+                }
+            }
+        }
+
+        len = fobj.getInlineProgressionDimension().getOptimum().getLength();
+        if (len.getEnum() != EN_AUTO) {
+            ipd = len.getValue();
+        } else {
+            len = fobj.getWidth();
+            if (len.getEnum() != EN_AUTO) {
+                ipd = len.getValue();
+            }
+        }
+
+        // if auto then use the intrinsic size of the content scaled
+        // to the content-height and content-width
+        int cwidth = -1;
+        int cheight = -1;
+        len = fobj.getContentWidth();
+        if (len.getEnum() != EN_AUTO) {
+            if (len.getEnum() == EN_SCALE_TO_FIT) {
+                if (ipd != -1) {
+                    cwidth = ipd;
+                }
+            } else {
+                cwidth = len.getValue();
+            }
+        }
+        len = fobj.getContentHeight();
+        if (len.getEnum() != EN_AUTO) {
+            if (len.getEnum() == EN_SCALE_TO_FIT) {
+                if (bpd != -1) {
+                    cwidth = bpd;
+                }
+            } else {
+                cheight = len.getValue();
+            }
+        }
+
+        int scaling = fobj.getScaling();
+        if ((scaling == EN_UNIFORM) || (cwidth == -1) || cheight == -1) {
+            if (cwidth == -1 && cheight == -1) {
+                cwidth = fobj.getIntrinsicWidth();
+                cheight = fobj.getIntrinsicHeight();
+            } else if (cwidth == -1) {
+                cwidth = (int)(fobj.getIntrinsicWidth() * (double)cheight 
+                    / fobj.getIntrinsicHeight());
+            } else if (cheight == -1) {
+                cheight = (int)(fobj.getIntrinsicHeight() * (double)cwidth 
+                    / fobj.getIntrinsicWidth());
+            } else {
+                // adjust the larger
+                double rat1 = cwidth / fobj.getIntrinsicWidth();
+                double rat2 = cheight / fobj.getIntrinsicHeight();
+                if (rat1 < rat2) {
+                    // reduce cheight
+                    cheight = (int)(rat1 * fobj.getIntrinsicHeight());
+                } else if (rat1 > rat2) {
+                    cwidth = (int)(rat2 * fobj.getIntrinsicWidth());
+                }
+            }
+        }
+
+        if (ipd == -1) {
+            ipd = cwidth;
+        }
+        if (bpd == -1) {
+            bpd = cheight;
+        }
+
+        boolean clip = false;
+        if (cwidth > ipd || cheight > bpd) {
+            int overflow = fobj.getOverflow();
+            if (overflow == EN_HIDDEN) {
+                clip = true;
+            } else if (overflow == EN_ERROR_IF_OVERFLOW) {
+                fobj.getLogger().error("Instream foreign object overflows the viewport: clipping");
+                clip = true;
+            }
+        }
+
+        int xoffset = fobj.computeXOffset(ipd, cwidth);
+        int yoffset = fobj.computeYOffset(bpd, cheight);
+
+        Rectangle2D placement = new Rectangle2D.Float(xoffset, yoffset, cwidth, cheight);
+
+        org.w3c.dom.Document doc = child.getDOMDocument();
+        String ns = child.getDocumentNamespace();
+
+        //fobj.childNodes = null; This is bad for i-f-o in static-content!!!!!
+        ForeignObject foreign = new ForeignObject(doc, ns);
+
+        Viewport vp = new Viewport(foreign);
+        vp.setIPD(ipd);
+        vp.setBPD(bpd);
+        vp.setContentPosition(placement);
+        vp.setClip(clip);
+        vp.setOffset(0);
+
+        // Common Border, Padding, and Background Properties
+        TraitSetter.addBorders(vp, fobj.getCommonBorderPaddingBackground());
+        TraitSetter.addBackground(vp, fobj.getCommonBorderPaddingBackground());
+
+        return vp;
+    }
+    
+    /**
+     * @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#addId()
+     */
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java b/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java
new file mode 100644 (file)
index 0000000..63568bd
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2004-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.layoutmgr.inline;
+
+import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
+import org.apache.fop.layoutmgr.KnuthBox;
+import org.apache.fop.layoutmgr.Position;
+
+public class KnuthInlineBox extends KnuthBox {
+    
+    private int lead;
+    private int total;
+    private int middle;
+    private FootnoteBodyLayoutManager footnoteBodyLM = null;
+
+    /**
+     * Create a new KnuthBox.
+     *
+     * @param w    the width of this box
+     * @param l    the height of this box above the main baseline
+     * @param t    the total height of this box
+     * @param m    the height of this box above and below the middle baseline
+     * @param pos  the Position stored in this box
+     * @param bAux is this box auxiliary?
+     */
+    public KnuthInlineBox(int w, int l, int t, int m, Position pos, boolean bAux) {
+        super(w, pos, bAux);
+        lead = l;
+        total = t;
+        middle = m;
+    }
+
+    /**
+     * @return the height of this box above the main baseline.
+     */
+    public int getLead() {
+        return lead;
+    }
+
+    /**
+     * @return the total height of this box.
+     */
+    public int getTotal() {
+        return total;
+    }
+
+    /**
+     * @return the height of this box above and below the middle baseline.
+     */
+    public int getMiddle() {
+        return middle;
+    }
+
+    /**
+     * @param fblm the FootnoteBodyLM this box must hold a reference to
+     */
+    public void setFootnoteBodyLM(FootnoteBodyLayoutManager fblm) {
+        footnoteBodyLM = fblm;
+    }
+
+    /**
+     * @return the FootnoteBodyLM this box holds a reference to
+     */
+    public FootnoteBodyLayoutManager getFootnoteBodyLM() {
+        return footnoteBodyLM;
+    }
+
+    /**
+     * @return true if this box holds a reference to a FootnoteBodyLM
+     */
+    public boolean isAnchor() {
+        return (footnoteBodyLM != null);
+    }
+    
+    
+    /** @see java.lang.Object#toString() */
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        sb.append(" lead=").append(lead);
+        sb.append(" total=").append(total);
+        sb.append(" middle=").append(middle);
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java
new file mode 100644 (file)
index 0000000..0bfa388
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.FilledArea;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.Space;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.datatypes.PercentBase;
+import org.apache.fop.fo.flow.Leader;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.KnuthPossPosIter;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.traits.MinOptMax;
+
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * LayoutManager for the fo:leader formatting object
+ */
+public class LeaderLayoutManager extends LeafNodeLayoutManager {
+    private Leader fobj;
+    Font font = null;
+    
+    private LinkedList contentList = null;
+    private ContentLayoutManager clm = null;
+
+    /**
+     * Constructor
+     *
+     * @param node the formatting object that creates this area
+     * @todo better null checking of font object
+     */
+    public LeaderLayoutManager(Leader node) {
+        super(node);
+        fobj = node;
+        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
+        // the property leader-alignment does not affect vertical positioning
+        // (see section 7.21.1 in the XSL Recommendation)
+        // setAlignment(node.getLeaderAlignment());
+        setAlignment(fobj.getVerticalAlign());
+    }
+
+    public InlineArea get(LayoutContext context) {
+        return getLeaderInlineArea();
+    }
+
+    protected MinOptMax getAllocationIPD(int refIPD) {
+        return getLeaderAllocIPD(refIPD);
+    }
+
+    private MinOptMax getLeaderAllocIPD(int ipd) {
+        // length of the leader
+        fobj.setLayoutDimension(PercentBase.BLOCK_IPD, ipd);
+        int opt = fobj.getLeaderLength().getOptimum().getLength().getValue();
+        int min = fobj.getLeaderLength().getMinimum().getLength().getValue();
+        int max = fobj.getLeaderLength().getMaximum().getLength().getValue();
+        return new MinOptMax(min, opt, max);
+    }
+
+    private InlineArea getLeaderInlineArea() {
+        InlineArea leaderArea = null;
+
+        if (fobj.getLeaderPattern() == EN_RULE) {
+            org.apache.fop.area.inline.Leader leader = 
+                new org.apache.fop.area.inline.Leader();
+            leader.setRuleStyle(fobj.getRuleStyle());
+            leader.setRuleThickness(fobj.getRuleThickness().getValue());
+            leaderArea = leader;
+        } else if (fobj.getLeaderPattern() == EN_SPACE) {
+            leaderArea = new Space();
+        } else if (fobj.getLeaderPattern() == EN_DOTS) {
+            TextArea t = new TextArea();
+            char dot = '.'; // userAgent.getLeaderDotCharacter();
+
+            t.setTextArea("" + dot);
+            t.setIPD(font.getCharWidth(dot));
+            t.addTrait(Trait.FONT_NAME, font.getFontName());
+            t.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize()));
+            int width = font.getCharWidth(dot);
+            Space spacer = null;
+            if (fobj.getLeaderPatternWidth().getValue() > width) {
+                spacer = new Space();
+                spacer.setIPD(fobj.getLeaderPatternWidth().getValue() - width);
+                width = fobj.getLeaderPatternWidth().getValue();
+            }
+            FilledArea fa = new FilledArea();
+            fa.setUnitWidth(width);
+            fa.addChildArea(t);
+            if (spacer != null) {
+                fa.addChildArea(spacer);
+            }
+            fa.setBPD(font.getAscender());
+
+            leaderArea = fa;
+        } else if (fobj.getLeaderPattern() == EN_USECONTENT) {
+            if (fobj.getChildNodes() == null) {
+                fobj.getLogger().error("Leader use-content with no content");
+                return null;
+            }
+
+            // child FOs are assigned to the InlineStackingLM
+            fobjIter = null;
+            
+            // get breaks then add areas to FilledArea
+            FilledArea fa = new FilledArea();
+
+            clm = new ContentLayoutManager(fa, this);
+            clm.setUserAgent(fobj.getUserAgent());
+            addChildLM(clm);
+
+            InlineLayoutManager lm;
+            lm = new InlineLayoutManager(fobj);
+            clm.addChildLM(lm);
+
+            contentList = clm.getNextKnuthElements(new LayoutContext(0), 0);
+            int width = clm.getStackingSize();
+            Space spacer = null;
+            if (fobj.getLeaderPatternWidth().getValue() > width) {
+                spacer = new Space();
+                spacer.setIPD(fobj.getLeaderPatternWidth().getValue() - width);
+                width = fobj.getLeaderPatternWidth().getValue();
+            }
+            fa.setUnitWidth(width);
+            if (spacer != null) {
+                fa.addChildArea(spacer);
+            }
+            leaderArea = fa;
+        }
+        return leaderArea;
+     }
+
+    protected void offsetArea(InlineArea area, LayoutContext context) {
+        int pattern = fobj.getLeaderPattern();
+        int bpd = area.getBPD();
+
+        switch (pattern) {
+            case EN_RULE: 
+                switch (verticalAlignment) {
+                    case EN_TOP:
+                        area.setOffset(0);
+                    break;
+                    case EN_MIDDLE:
+                        area.setOffset(context.getMiddleBaseline() - bpd / 2);
+                    break;
+                    case EN_BOTTOM:
+                        area.setOffset(context.getLineHeight() - bpd);
+                    break;
+                    case EN_BASELINE: // fall through
+                    default:
+                        area.setOffset(context.getBaseline() - bpd);
+                    break;
+                }
+            break;
+            case EN_DOTS: 
+                switch (verticalAlignment) {
+                    case EN_TOP:
+                        area.setOffset(0);
+                    break;
+                    case EN_MIDDLE:
+                        area.setOffset(context.getMiddleBaseline());
+                    break;
+                    case EN_BOTTOM:
+                        area.setOffset(context.getLineHeight() - bpd + font.getAscender());
+                    break;
+                    case EN_BASELINE: // fall through
+                    default:
+                        area.setOffset(context.getBaseline());
+                    break;
+                }
+            break;
+            case EN_SPACE: 
+                // nothing to do
+            break;
+            case EN_USECONTENT: 
+                switch (verticalAlignment) {
+                    case EN_TOP:
+                        area.setOffset(0);
+                    break;
+                    case EN_MIDDLE:
+                        area.setOffset(context.getMiddleBaseline());
+                    break;
+                    case EN_BOTTOM:
+                        area.setOffset(context.getLineHeight() - bpd);
+                    break;
+                    case EN_BASELINE: // fall through
+                    default:
+                        area.setOffset(context.getBaseline());
+                    break;
+                }
+            break;
+        }
+    }
+
+    public void addAreas(PositionIterator posIter, LayoutContext context) {
+        if (fobj.getLeaderPattern() != EN_USECONTENT) {
+            // use LeafNodeLayoutManager.addAreas()
+            super.addAreas(posIter, context);
+        } else {
+            addId();
+
+            widthAdjustArea(curArea, context);
+
+            // add content areas
+            KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size());
+            clm.addAreas(contentIter, context);
+            offsetArea(curArea, context);
+
+            parentLM.addChildArea(curArea);
+
+            while (posIter.hasNext()) {
+                posIter.next();
+            }
+        }
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        MinOptMax ipd;
+        curArea = get(context);
+        LinkedList returnList = new LinkedList();
+
+        if (curArea == null) {
+            setFinished(true);
+            return null;
+        }
+
+        ipd = getAllocationIPD(context.getRefIPD());
+
+        int bpd = curArea.getBPD();
+        int lead = 0;
+        int total = 0;
+        int middle = 0;
+        switch (verticalAlignment) {
+            case EN_MIDDLE  : middle = bpd / 2 ;
+                                         break;
+            case EN_TOP     : // fall through
+            case EN_BOTTOM  : total = bpd;
+                                         break;
+            case EN_BASELINE: // fall through
+            default:                     lead = bpd;
+                                         break;
+        }
+
+        // create the AreaInfo object to store the computed values
+        areaInfo = new AreaInfo((short) 0, ipd, false,
+                                lead, total, middle);
+
+        // node is a fo:Leader
+        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
+                                    areaInfo.middle,
+                                    new LeafPosition(this, -1), true));
+        returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                        new LeafPosition(this, -1), true));
+        returnList.add
+            (new KnuthGlue(areaInfo.ipdArea.opt,
+                           areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
+                           areaInfo.ipdArea.opt - areaInfo.ipdArea.min, 
+                           new LeafPosition(this, 0), false));
+        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
+                                    areaInfo.middle,
+                                    new LeafPosition(this, -1), true));
+
+        setFinished(true);
+        return returnList;
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        // use the AbstractLayoutManager.hyphenate() null implementation
+        super.hyphenate(pos, hc);
+    }
+
+    public boolean applyChanges(List oldList) {
+        setFinished(false);
+        return false;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              int flaggedPenalty,
+                                              int alignment) {
+        if (isFinished()) {
+            return null;
+        }
+
+        LinkedList returnList = new LinkedList();
+
+        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
+                                    areaInfo.middle,
+                                    new LeafPosition(this, -1), true));
+        returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                        new LeafPosition(this, -1), true));
+        returnList.add
+            (new KnuthGlue(areaInfo.ipdArea.opt,
+                           areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
+                           areaInfo.ipdArea.opt - areaInfo.ipdArea.min, 
+                           new LeafPosition(this, 0), false));
+        returnList.add(new KnuthInlineBox(0, areaInfo.lead, areaInfo.total,
+                                    areaInfo.middle,
+                                    new LeafPosition(this, -1), true));
+
+        setFinished(true);
+        return returnList;
+    }
+
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LeafNodeLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LeafNodeLayoutManager.java
new file mode 100644 (file)
index 0000000..7fe310f
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.area.Area;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.fo.FObj;
+import org.apache.fop.layoutmgr.AbstractLayoutManager;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.traits.MinOptMax;
+
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * Base LayoutManager for leaf-node FObj, ie: ones which have no children.
+ * These are all inline objects. Most of them cannot be split (Text is
+ * an exception to this rule.)
+ * This class can be extended to handle the creation and adding of the
+ * inline area.
+ */
+public abstract class LeafNodeLayoutManager extends AbstractLayoutManager 
+                                   implements InlineLevelLayoutManager {
+    /**
+     * The inline area that this leafnode will add.
+     */
+    protected InlineArea curArea = null;
+    protected int verticalAlignment;
+    private int lead;
+    private MinOptMax ipd;
+
+    protected boolean bSomethingChanged = false;
+    protected AreaInfo areaInfo = null;
+
+    /**
+     * Store information about the inline area
+     */
+    protected class AreaInfo {
+        protected short iLScount;
+        protected MinOptMax ipdArea;
+        protected boolean bHyphenated;
+        protected int lead;
+        protected int total;
+        protected int middle;
+
+        public AreaInfo(short iLS, MinOptMax ipd, boolean bHyph,
+                        int l, int t, int m) {
+            iLScount = iLS;
+            ipdArea = ipd;
+            bHyphenated = bHyph;
+            lead = l;
+            total = t;
+            middle = m;
+        }
+    }
+
+
+    /**
+     * Create a Leaf node layout mananger.
+     * @param node the FObj to attach to this LM.
+     */
+    public LeafNodeLayoutManager(FObj node) {
+        super(node);
+    }
+
+    /**
+     * Create a Leaf node layout mananger.
+     */
+    public LeafNodeLayoutManager() {
+    }
+
+    /**
+     * get the inline area.
+     * @param context the context used to create the area
+     * @return the current inline area for this layout manager
+     */
+    public InlineArea get(LayoutContext context) {
+        return curArea;
+    }
+
+    /**
+     * Check if this inline area is resolved due to changes in
+     * page or ipd.
+     * Currently not used.
+     * @return true if the area is resolved when adding
+     */
+    public boolean resolved() {
+        return false;
+    }
+
+    /**
+     * Set the current inline area.
+     * @param ia the inline area to set for this layout manager
+     */
+    public void setCurrentArea(InlineArea ia) {
+        curArea = ia;
+    }
+
+    /**
+     * Set the alignment of the inline area.
+     * @param al the vertical alignment positioning
+     */
+    public void setAlignment(int al) {
+        verticalAlignment = al;
+    }
+
+    /**
+     * Set the lead for this inline area.
+     * The lead is the distance from the top of the object
+     * to the baseline.
+     * @param l the lead value
+     */
+    public void setLead(int l) {
+        lead = l;
+    }
+    
+    /** @return the lead value (distance from the top of the object to the baseline) */
+    public int getLead() {
+        return this.lead;
+    }
+
+    /**
+     * This is a leaf-node, so this method is never called.
+     * @param childArea the childArea to add
+     */
+    public void addChildArea(Area childArea) {
+    }
+
+    /**
+     * This is a leaf-node, so this method is never called.
+     * @param childArea the childArea to get the parent for
+     * @return the parent area
+     */
+    public Area getParentArea(Area childArea) {
+        return null;
+    }
+
+    /**
+     * Get the allocation ipd of the inline area.
+     * This method may be overridden to handle percentage values.
+     * @param refIPD the ipd of the parent reference area
+     * @return the min/opt/max ipd of the inline area
+     */
+    protected MinOptMax getAllocationIPD(int refIPD) {
+        return new MinOptMax(curArea.getIPD());
+    }
+
+    /**
+     * Add the area for this layout manager.
+     * This adds the single inline area to the parent.
+     * @param posIter the position iterator
+     * @param context the layout context for adding the area
+     */
+    public void addAreas(PositionIterator posIter, LayoutContext context) {
+        addId();
+
+        InlineArea area = getEffectiveArea();
+        if (area.getAllocIPD() > 0 || area.getAllocBPD() > 0) {
+            offsetArea(area, context);
+            widthAdjustArea(area, context);
+            parentLM.addChildArea(area);
+        }
+
+        while (posIter.hasNext()) {
+            posIter.next();
+        }
+    }
+
+    /**
+     * @return the effective area to be added to the area tree. Normally, this is simply "curArea"
+     * but in the case of page-number(-citation) curArea is cloned, updated and returned.
+     */
+    protected InlineArea getEffectiveArea() {
+        return curArea;
+    }
+    
+    protected void addId() {
+        // Do nothing here, overriden in subclasses that have an 'id' property.
+    }
+    
+    /**
+     * Offset this area.
+     * Offset the inline area in the bpd direction when adding the
+     * inline area.
+     * This is used for vertical alignment.
+     * Subclasses should override this if necessary.
+     * @param area the inline area to be updated
+     * @param context the layout context used for adding the area
+     */
+    protected void offsetArea(InlineArea area, LayoutContext context) {
+        int bpd = area.getBPD();
+        switch (verticalAlignment) {
+            case EN_MIDDLE:
+                area.setOffset(context.getMiddleBaseline() - bpd / 2);
+            break;
+            case EN_TOP:
+                area.setOffset(context.getTopBaseline());
+            break;
+            case EN_BOTTOM:
+                area.setOffset(context.getBottomBaseline() - bpd);
+            break;
+            case EN_BASELINE:
+            default:
+                area.setOffset(context.getBaseline() - bpd);
+            break;
+        }
+    }
+
+    /**
+     * Adjust the width of the area when adding.
+     * This uses the min/opt/max values to adjust the with
+     * of the inline area by a percentage.
+     * @param area the inline area to be updated
+     * @param context the layout context for adding this area
+     */
+    protected void widthAdjustArea(InlineArea area, LayoutContext context) {
+        double dAdjust = context.getIPDAdjust();
+        int width = areaInfo.ipdArea.opt;
+        if (dAdjust < 0) {
+            width = (int) (width + dAdjust * (areaInfo.ipdArea.opt
+                                             - areaInfo.ipdArea.min));
+        } else if (dAdjust > 0) {
+            width = (int) (width + dAdjust * (areaInfo.ipdArea.max
+                                             - areaInfo.ipdArea.opt));
+        }
+        area.setIPD(width);
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        MinOptMax ipd;
+        curArea = get(context);
+
+        if (curArea == null) {
+            setFinished(true);
+            return null;
+        }
+        ipd = getAllocationIPD(context.getRefIPD());
+
+        int bpd = curArea.getBPD();
+        int lead = 0;
+        int total = 0;
+        int middle = 0;
+        switch (verticalAlignment) {
+            case EN_MIDDLE  : middle = bpd / 2 ;
+                                         lead = bpd / 2 ;
+                                         break;
+            case EN_TOP     : total = bpd;
+                                         break;
+            case EN_BOTTOM  : total = bpd;
+                                         break;
+            case EN_BASELINE:
+            default:                     
+                //lead = bpd;
+                lead = getLead();
+                total = bpd;
+                break;
+        }
+
+        // create the AreaInfo object to store the computed values
+        areaInfo = new AreaInfo((short) 0, ipd, false,
+                                lead, total, middle);
+
+        // node is a fo:ExternalGraphic, fo:InstreamForeignObject,
+        // fo:PageNumber or fo:PageNumberCitation
+        LinkedList returnList = new LinkedList();
+        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+                                    areaInfo.total, areaInfo.middle,
+                                    new LeafPosition(this, 0), false));
+        setFinished(true);
+        return returnList;
+    }
+
+    public List addALetterSpaceTo(List oldList) {
+        // return the unchanged elements
+        return oldList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+    }
+
+    public boolean applyChanges(List oldList) {
+        setFinished(false);
+        return false;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              /*int flaggedPenalty,*/
+                                              int alignment) {
+        if (isFinished()) {
+            return null;
+        }
+
+        LinkedList returnList = new LinkedList();
+
+        // fobj is a fo:ExternalGraphic, fo:InstreamForeignObject,
+        // fo:PageNumber or fo:PageNumberCitation
+        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.lead,
+                                          areaInfo.total, areaInfo.middle,
+                                          new LeafPosition(this, 0), true));
+
+        setFinished(true);
+        return returnList;
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
new file mode 100644 (file)
index 0000000..01955ee
--- /dev/null
@@ -0,0 +1,1517 @@
+/*
+ * Copyright 1999-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: LineLayoutManager.java,v 1.17 2004/04/02 10:38:29 cbowditch Exp $ */
+
+package org.apache.fop.layoutmgr.inline;
+
+import org.apache.fop.datatypes.Length;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.flow.Block;
+import org.apache.fop.fo.properties.CommonHyphenation;
+import org.apache.fop.hyphenation.Hyphenation;
+import org.apache.fop.hyphenation.Hyphenator;
+import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
+import org.apache.fop.layoutmgr.BreakingAlgorithm;
+import org.apache.fop.layoutmgr.ElementListObserver;
+import org.apache.fop.layoutmgr.KnuthBlockBox;
+import org.apache.fop.layoutmgr.KnuthBox;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.KnuthPossPosIter;
+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.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.layoutmgr.SpaceSpecifier;
+import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode;
+import org.apache.fop.area.LineArea;
+
+import java.util.ListIterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * LayoutManager for lines. It builds one or more lines containing
+ * inline areas generated by its sub layout managers.
+ * A break is found for each line which may contain one of more
+ * breaks from the child layout managers.
+ * Once a break is found then it is return for the parent layout
+ * manager to handle.
+ * When the areas are being added to the page this manager
+ * creates a line area to contain the inline areas added by the
+ * child layout managers.
+ */
+public class LineLayoutManager extends InlineStackingLayoutManager 
+                               implements BlockLevelLayoutManager {
+
+    private Block fobj; 
+    
+    private void initialize() {
+        bTextAlignment = fobj.getTextAlign();
+        bTextAlignmentLast = fobj.getTextAlignLast();
+        textIndent = fobj.getTextIndent();
+        hyphProps = fobj.getCommonHyphenation();
+        
+        //
+        if (bTextAlignment != EN_JUSTIFY && bTextAlignmentLast == EN_JUSTIFY) {
+            effectiveAlignment = 0;
+        } else {
+            effectiveAlignment = bTextAlignment;
+        }
+    }
+
+    /**
+     * Private class to store information about inline breaks.
+     * Each value holds the start and end indexes into a List of
+     * inline break positions.
+     */
+    private static class LineBreakPosition extends LeafPosition {
+        // int iPos;
+        int iParIndex; // index of the Paragraph this Position refers to
+        int availableShrink;
+        int availableStretch;
+        int difference;
+        double dAdjust; // Percentage to adjust (stretch or shrink)
+        double ipdAdjust; // Percentage to adjust (stretch or shrink)
+        int startIndent;
+        int lineHeight;
+        int lineWidth;
+        int baseline;
+        int topShift;
+        int bottomShift;
+
+        LineBreakPosition(LayoutManager lm, int index, int iBreakIndex,
+                          int shrink, int stretch, int diff,
+                          double ipdA, double adjust, int ind,
+                          int lh, int lw, int bl, int ts, int bs) {
+            super(lm, iBreakIndex);
+            availableShrink = shrink;
+            availableStretch = stretch;
+            difference = diff;
+            iParIndex = index;
+            ipdAdjust = ipdA;
+            dAdjust = adjust;
+            startIndent = ind;
+            lineHeight = lh;
+            lineWidth = lw;
+            baseline = bl;
+            topShift = ts;
+            bottomShift = bs;
+        }
+        
+    }
+
+
+    /** Break positions returned by inline content. */
+    private List vecInlineBreaks = new java.util.ArrayList();
+
+    private int bTextAlignment = EN_JUSTIFY;
+    private int bTextAlignmentLast;
+    private int effectiveAlignment;
+    private Length textIndent;
+    private int iIndents = 0;
+    private CommonHyphenation hyphProps;
+    //private LayoutProps layoutProps;
+
+    private int lineHeight;
+    private int lead;
+    private int follow;
+    // offset of the middle baseline with respect to the main baseline
+    private int middleShift;
+
+    private List knuthParagraphs = null;
+    private int iReturnedLBP = 0;
+    private int iStartElement = 0;
+    private int iEndElement = 0;
+
+    //     parameters of Knuth's algorithm:
+    // penalty value for flagged penalties
+    private int flaggedPenalty = 50;
+
+    private LineLayoutPossibilities lineLayouts;
+    private List lineLayoutsList;
+    private int iLineWidth = 0;
+
+    // this constant is used to create elements when text-align is center:
+    // every TextLM descendant of LineLM must use the same value, 
+    // otherwise the line breaking algorithm does not find the right
+    // break point
+    public static final int DEFAULT_SPACE_WIDTH = 3336;
+
+
+    // this class is used to remember
+    // which was the first element in the paragraph
+    // returned by each LM
+    private class Update {
+        private InlineLevelLayoutManager inlineLM;
+        private int iFirstIndex;
+
+        public Update(InlineLevelLayoutManager lm, int index) {
+            inlineLM = lm;
+            iFirstIndex = index;
+        }
+    }
+
+    // this class represents a paragraph
+    private class Paragraph extends KnuthSequence {
+        // space at the end of the last line (in millipoints)
+        private MinOptMax lineFiller;
+        private int textAlignment;
+        private int textAlignmentLast;
+        private int textIndent;
+        private int lineWidth;
+        // the LM which created the paragraph
+        private LineLayoutManager layoutManager;
+
+        public Paragraph(LineLayoutManager llm, int alignment, int alignmentLast,
+                         int indent) {
+            super();
+            layoutManager = llm;
+            textAlignment = alignment;
+            textAlignmentLast = alignmentLast;
+            textIndent = indent;
+        }
+
+        public void startParagraph(int lw) {
+            lineWidth = lw;
+            startSequence();
+        }
+
+        public void startSequence() {
+            // set the minimum amount of empty space at the end of the
+            // last line
+            if (bTextAlignment == EN_CENTER) {
+                lineFiller = new MinOptMax(0); 
+            } else {
+                lineFiller = new MinOptMax(0, (int)(lineWidth / 12), lineWidth); 
+            }
+
+            // add auxiliary elements at the beginning of the paragraph
+            if (bTextAlignment == EN_CENTER && bTextAlignmentLast != EN_JUSTIFY) {
+                this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
+                                       null, false));
+                ignoreAtStart ++;
+            }
+
+            // add the element representing text indentation
+            // at the beginning of the first paragraph
+            if (knuthParagraphs.size() == 0
+                        && fobj.getTextIndent().getValue() != 0) {
+                this.add(new KnuthInlineBox(fobj.getTextIndent().getValue(), 0, 0, 0,
+                                      null, false));
+                ignoreAtStart ++;
+            }
+        }
+
+        public void endParagraph() {
+            KnuthSequence finishedPar = this.endSequence();
+            if (finishedPar != null) {
+                knuthParagraphs.add(finishedPar);
+            }
+        }
+
+        public KnuthSequence endSequence() {
+            // remove glue and penalty item at the end of the paragraph
+            while (this.size() > ignoreAtStart
+                   && !((KnuthElement)this.get(this.size() - 1)).isBox()) {
+                this.remove(this.size() - 1);
+            }
+            if (this.size() > ignoreAtStart) {
+                if (bTextAlignment == EN_CENTER
+                    && bTextAlignmentLast != EN_JUSTIFY) {
+                    this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
+                                           null, false));
+                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                              false, null, false));
+                    ignoreAtEnd = 2;
+                } else if (bTextAlignmentLast != EN_JUSTIFY) {
+                    // add the elements representing the space
+                    // at the end of the last line
+                    // and the forced break
+                    this.add(new KnuthPenalty(0, KnuthElement.INFINITE, 
+                                              false, null, false));
+                    this.add(new KnuthGlue(lineFiller.opt, 
+                            lineFiller.max - lineFiller.opt, 
+                            lineFiller.opt - lineFiller.min, null, false));
+                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                              false, null, false));
+                    ignoreAtEnd = 3;
+                } else {
+                    // add only the element representing the forced break
+                    this.add(new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                              false, null, false));
+                    ignoreAtEnd = 1;
+                }
+                return this;
+            } else {
+                this.clear();
+                return null;
+            }
+        }
+
+    }
+
+    private class LineBreakingAlgorithm extends BreakingAlgorithm {
+        private LineLayoutManager thisLLM;
+        private int pageAlignment;
+        private int activePossibility;
+        private int addedPositions;
+        private int textIndent;
+        private int fillerMinWidth;
+        private int lineHeight;
+        private int lead;
+        private int follow;
+        private int middleshift;
+        private int maxDiff;
+        private static final double MAX_DEMERITS = 10e6;
+
+        public LineBreakingAlgorithm (int pageAlign,
+                                      int textAlign, int textAlignLast,
+                                      int indent, int fillerWidth,
+                                      int lh, int ld, int fl, int ms, boolean first,
+                                      LineLayoutManager llm) {
+            super(textAlign, textAlignLast, first, false);
+            pageAlignment = pageAlign;
+            textIndent = indent;
+            fillerMinWidth = fillerWidth;
+            lineHeight = lh;
+            lead = ld;
+            follow = fl;
+            middleshift = ms;
+            thisLLM = llm;
+            activePossibility = -1;
+            maxDiff = fobj.getWidows() >= fobj.getOrphans() 
+                    ? fobj.getWidows()
+                    : fobj.getOrphans();
+        }
+
+        public void updateData1(int lineCount, double demerits) {
+            lineLayouts.addPossibility(lineCount, demerits);
+            log.trace("Layout possibility in " + lineCount + " lines; break at position:");
+        }
+
+        public void updateData2(KnuthNode bestActiveNode,
+                                KnuthSequence par,
+                                int total) {
+            // compute indent and adjustment ratio, according to
+            // the value of text-align and text-align-last
+            int indent = 0;
+            int difference = (bestActiveNode.line < total) ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth;
+            int textAlign = (bestActiveNode.line < total) ? alignment : alignmentLast;
+            indent += (textAlign == Constants.EN_CENTER) ?
+                          difference / 2 :
+                          (textAlign == Constants.EN_END) ? difference : 0;
+            indent += (bestActiveNode.line == 1 && bFirst) ? 
+                          textIndent : 0;
+            double ratio = (textAlign == Constants.EN_JUSTIFY
+                            || bestActiveNode.adjustRatio < 0) ? bestActiveNode.adjustRatio : 0;
+
+            // add nodes at the beginning of the list, as they are found
+            // backwards, from the last one to the first one
+
+            // the first time this method is called, initialize activePossibility
+            if (activePossibility == -1) {
+                activePossibility = 0;
+                addedPositions = 0;
+            }
+
+            if (addedPositions == lineLayouts.getLineCount(activePossibility)) {
+                activePossibility ++;
+                addedPositions = 0;
+                //System.out.println(" ");
+            }
+
+            //System.out.println("LLM> (" + (lineLayouts.getLineNumber(activePossibility) - addedPositions) + ") difference = " + difference + " ratio = " + ratio);
+            lineLayouts.addBreakPosition(makeLineBreakPosition(par,
+                                                               (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1: 0),
+                                                               bestActiveNode.position,
+                                                               bestActiveNode.availableShrink - (addedPositions > 0 ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min), bestActiveNode.availableStretch, difference, ratio, indent),
+                                         activePossibility);
+            addedPositions ++;
+        }
+
+        /* reset activePossibility, as if breakpoints have not yet been computed
+         */
+        public void resetAlgorithm() {
+            activePossibility = -1;
+        }
+
+        private LineBreakPosition makeLineBreakPosition(KnuthSequence par,
+                                                        int firstElementIndex,
+                                                        int lastElementIndex,
+                                                        int availableShrink, int availableStretch, int difference,
+                                                        double ratio,
+                                                        int indent) {
+            // line height calculation
+
+            int halfLeading = (lineHeight - lead - follow) / 2;
+            // height before the main baseline
+            int lineLead = lead;
+            // maximum size of top and bottom alignment
+            int maxtb = follow;
+            // max size of middle alignment before and after the middle baseline
+            int middlefollow = maxtb;
+            // true if this line contains only zero-height, auxiliary boxes
+            // and the actual line width is 0; in this case, the line "collapses"
+            // i.e. the line area will have bpd = 0
+            boolean bZeroHeightLine = (difference == iLineWidth);
+
+            // if line-stacking-strategy is "font-height", the line height
+            // is not affected by its content
+            if (fobj.getLineStackingStrategy() != EN_FONT_HEIGHT) {
+                ListIterator inlineIterator
+                    = par.listIterator(firstElementIndex);
+                for (int j = firstElementIndex;
+                     j <= lastElementIndex;
+                     j++) {
+                    KnuthElement element = (KnuthElement) inlineIterator.next();
+                    if (element.isBox()) {
+                        if (((KnuthInlineBox) element).getLead() > lineLead) {
+                            lineLead = ((KnuthInlineBox) element).getLead();
+                        }
+                        if (((KnuthInlineBox) element).getTotal() > maxtb) {
+                            maxtb = ((KnuthInlineBox) element).getTotal();
+                        }
+                        if (((KnuthInlineBox) element).getMiddle() > lineLead + middleShift) {
+                            lineLead += ((KnuthInlineBox) element).getMiddle()
+                                        - lineLead - middleShift;
+                        }
+                        if (((KnuthInlineBox) element).getMiddle() > middlefollow - middleShift) {
+                            middlefollow += ((KnuthInlineBox) element).getMiddle()
+                                            - middlefollow + middleShift;
+                        }
+                        if (bZeroHeightLine
+                            && (!element.isAuxiliary()
+                                || ((KnuthInlineBox) element).getTotal() > 0
+                                || ((KnuthInlineBox) element).getLead() > 0
+                                || ((KnuthInlineBox) element).getMiddle() > 0)) {
+                            bZeroHeightLine = false;
+                        }
+                    }
+                }
+
+                if (maxtb - lineLead > middlefollow) {
+                    middlefollow = maxtb - lineLead;
+                }
+            }
+
+            constantLineHeight = lineLead + middlefollow + (lineHeight - lead - follow);
+
+            if (bZeroHeightLine) {
+                return new LineBreakPosition(thisLLM,
+                                             knuthParagraphs.indexOf(par),
+                                             lastElementIndex,
+                                             availableShrink, availableStretch, difference, ratio, 0, indent,
+                                             0, iLineWidth,
+                                             0, 0, 0);
+            } else {
+                return new LineBreakPosition(thisLLM,
+                                             knuthParagraphs.indexOf(par),
+                                             lastElementIndex,
+                                             availableShrink, availableStretch, difference, ratio, 0, indent,
+                                             lineLead + middlefollow + (lineHeight - lead - follow), iLineWidth,
+                                             lineLead + halfLeading,
+                                             - lineLead, middlefollow);
+            }
+        }
+
+        public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
+                                      double threshold, boolean force,
+                                      boolean hyphenationAllowed) {
+            return super.findBreakingPoints(par, /*lineWidth,*/ 
+                    threshold, force, hyphenationAllowed);
+        }
+
+        protected int filterActiveNodes() {
+            KnuthNode bestActiveNode = null;
+
+            if (pageAlignment == EN_JUSTIFY) {
+                // leave all active nodes and find the optimum line number
+                //System.out.println("LBA.filterActiveNodes> " + activeNodeCount + " layouts");
+                for (int i = startLine; i < endLine; i++) {
+                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
+                        //System.out.println("                       + lines = " + node.line + " demerits = " + node.totalDemerits);
+                        bestActiveNode = compareNodes(bestActiveNode, node);
+                    }
+                }
+
+                // scan the node set once again and remove some nodes
+                //System.out.println("LBA.filterActiveList> layout selection");
+                for (int i = startLine; i < endLine; i++) {
+                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
+                        //if (Math.abs(node.line - bestActiveNode.line) > maxDiff) {
+                        //if (false) {
+                        if (node.line != bestActiveNode.line
+                            && node.totalDemerits > MAX_DEMERITS) {
+                            //System.out.println("                     XXX lines = " + node.line + " demerits = " + node.totalDemerits);
+                            removeNode(i, node);
+                        } else {
+                            //System.out.println("                      ok lines = " + node.line + " demerits = " + node.totalDemerits);
+                        }
+                    }
+                }
+            } else {
+                // leave only the active node with fewest total demerits
+                for (int i = startLine; i < endLine; i++) {
+                    for (KnuthNode node = getNode(i); node != null; node = node.next) {
+                        bestActiveNode = compareNodes(bestActiveNode, node);
+                        if (node != bestActiveNode) {
+                            removeNode(i, node);
+                        }
+                    }
+                }
+            }
+            return bestActiveNode.line;
+        }
+    }
+
+      
+    private int constantLineHeight = 12000;
+      
+
+    /**
+     * Create a new Line Layout Manager.
+     * This is used by the block layout manager to create
+     * line managers for handling inline areas flowing into line areas.
+     *
+     * @param lh the default line height
+     * @param l the default lead, from top to baseline
+     * @param f the default follow, from baseline to bottom
+     */
+    public LineLayoutManager(Block block, int lh, int l, int f, int ms) {
+        super(block);
+        fobj = block;
+        // the child FObj are owned by the parent BlockLM
+        // this LM has all its childLMs preloaded
+        fobjIter = null;
+        lineHeight = lh;
+        lead = l;
+        follow = f;
+        middleShift = ms;
+        initialize(); // Normally done when started by parent!
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+        // Get a break from currently active child LM
+        // Set up constraints for inline level managers
+        InlineLevelLayoutManager curLM ; // currently active LM
+
+        // IPD remaining in line
+        MinOptMax availIPD = context.getStackLimit();
+
+        clearPrevIPD();
+        int iPrevLineEnd = vecInlineBreaks.size();
+
+        if (iPrevLineEnd == 0 && bTextAlignment == EN_START) {
+            availIPD.subtract(new MinOptMax(textIndent.getValue()));
+        }
+
+        //PHASE 1: Create Knuth elements
+        if (knuthParagraphs == null) {
+            // it's the first time this method is called
+            knuthParagraphs = new ArrayList();
+
+            // here starts Knuth's algorithm
+            //TODO availIPD should not really be used here, so we can later support custom line
+            //widths for for each line (side-floats, differing available IPD after page break)
+            collectInlineKnuthElements(context, availIPD);
+        } else {
+            // this method has been called before
+            // all line breaks are already calculated
+        }
+
+        // return finished when there's no content
+        if (knuthParagraphs.size() == 0) {
+            setFinished(true);
+            return null;
+        }
+
+        //PHASE 2: Create line breaks
+        return findOptimalLineBreakingPoints(alignment);
+        /*
+        LineBreakPosition lbp = null;
+        if (breakpoints == null) {
+            // find the optimal line breaking points for each paragraph
+            breakpoints = new ArrayList();
+            ListIterator paragraphsIterator
+                = knuthParagraphs.listIterator(knuthParagraphs.size());
+            Paragraph currPar = null;
+            while (paragraphsIterator.hasPrevious()) {
+                currPar = (Paragraph) paragraphsIterator.previous();
+                findBreakingPoints(currPar, context.getStackLimit().opt);
+            }
+        }*/
+
+        //PHASE 3: Return lines
+
+        /*
+        // get a break point from the list
+        lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
+        if (iReturnedLBP == breakpoints.size()) {
+            setFinished(true);
+        }
+
+        BreakPoss curLineBP = new BreakPoss(lbp);
+        curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
+        curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
+        return curLineBP;
+        */
+    }
+
+    /**
+     * Phase 1 of Knuth algorithm: Collect all inline Knuth elements before determining line breaks.
+     * @param context the LayoutContext
+     * @param availIPD available IPD for line (should be removed!) 
+     */
+    private void collectInlineKnuthElements(LayoutContext context, MinOptMax availIPD) {
+        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);
+        while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
+            if ((returnedList
+                 = curLM.getNextKnuthElements(inlineLC,
+                                              effectiveAlignment))
+                != null) {
+                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);
+                    } 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());
+                    }
+                    // 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());
+                    }
+                }
+
+                // 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();
+                    }
+                }
+
+                // 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));
+                    }
+                    knuthPar.endParagraph();
+                    knuthPar = new Paragraph(this, 
+                                             bTextAlignment, bTextAlignmentLast, 
+                                             textIndent.getValue());
+                    knuthPar.startParagraph(availIPD.opt);
+                    bPrevWasKnuthBox = false;
+                }
+            } else {
+                // curLM returned null; this can happen
+                // if it has nothing more to layout,
+                // so just iterate once more to see
+                // if there are other children
+            }
+        }
+        knuthPar.endParagraph();
+        ElementListObserver.observe(knuthPar, "line", null);
+    }
+
+    /**
+     * Find a set of breaking points.
+     * This method is called only once by getNextBreakPoss, and it 
+     * subsequently calls the other findBreakingPoints() method with 
+     * different parameters, until a set of breaking points is found.
+     *
+     * @param par       the list of elements that must be parted
+     *                  into lines
+     * @param lineWidth the desired length ot the lines
+     */
+    /*
+    private void findBreakingPoints(Paragraph par, int lineWidth) {
+        // maximum adjustment ratio permitted
+        float maxAdjustment = 1;
+
+        // first try
+        if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
+            // the first try failed, now try something different
+            log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
+            if (hyphProps.hyphenate == Constants.EN_TRUE) {
+                // consider every hyphenation point as a legal break
+                findHyphenationPoints(par);
+            } else {
+                // try with a higher threshold
+                maxAdjustment = 5;
+            }
+
+            if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
+                // the second try failed too, try with a huge threshold;
+                // if this fails too, use a different algorithm
+                log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
+                          + (hyphProps.hyphenate == Constants.EN_TRUE ? " and hyphenation" : ""));
+                maxAdjustment = 20;
+                if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) {
+                    log.debug("No set of breaking points found, using first-fit algorithm");
+                }
+            }
+        }
+    }
+    
+    private boolean findBreakingPoints(Paragraph par, int lineWidth,
+            double threshold, boolean force) {
+        KnuthParagraph knuthPara = new KnuthParagraph(par);
+        int lines = knuthPara.findBreakPoints(lineWidth, threshold, force);
+        if (lines == 0) {
+            return false;
+        }
+        
+        for (int i = lines-1; i >= 0; i--) {
+            int line = i+1;
+            if (log.isTraceEnabled()) {
+                log.trace("Making line from " + knuthPara.getStart(i) + " to " + 
+                           knuthPara.getEnd(i));
+            }
+            // compute indent and adjustment ratio, according to
+            // the value of text-align and text-align-last
+
+            int difference = knuthPara.getDifference(i);
+            if (line == lines) {
+                difference += par.lineFillerWidth;
+            }    
+            int textAlign = (line < lines)
+                ? bTextAlignment : bTextAlignmentLast;
+            int indent = (textAlign == EN_CENTER)
+                ? difference / 2
+                : (textAlign == EN_END) ? difference : 0;
+            indent += (line == 1 && knuthParagraphs.indexOf(par) == 0)
+                ? textIndent.getValue() : 0;
+            double ratio = (textAlign == EN_JUSTIFY)
+                ? knuthPara.getAdjustRatio(i) : 0;
+
+            int start = knuthPara.getStart(i);
+            int end = knuthPara.getEnd(i);
+            makeLineBreakPosition(par, start, end, 0, ratio, indent);
+        }
+        return true;        
+    }
+
+    private void makeLineBreakPosition(Paragraph par,
+                                       int firstElementIndex, int lastElementIndex,
+                                       int insertIndex, double ratio, int indent) {
+        // line height calculation
+
+        int halfLeading = (lineHeight - lead - follow) / 2;
+        // height above the main baseline
+        int lineLead = lead + halfLeading;
+        // maximum size of top and bottom alignment
+        int maxtb = follow + halfLeading;
+        // max size of middle alignment above and below the middle baseline
+        int middlefollow = maxtb;
+
+        ListIterator inlineIterator
+            = par.listIterator(firstElementIndex);
+        for (int j = firstElementIndex;
+             j <= lastElementIndex;
+             j++) {
+            KnuthElement element = (KnuthElement) inlineIterator.next();
+            if (element.isBox()) {
+                KnuthInlineBox box = (KnuthInlineBox)element;
+                if (box.getLead() > lineLead) {
+                    lineLead = box.getLead();
+                }
+                if (box.getTotal() > maxtb) {
+                    maxtb = box.getTotal();
+                }
+                if (box.getMiddle() > lineLead + middleShift) {
+                    lineLead += box.getMiddle()
+                                - lineLead - middleShift;
+                }
+                if (box.getMiddle() > middlefollow - middleShift) {
+                    middlefollow += box.getMiddle()
+                                    - middlefollow + middleShift;
+                }
+            }
+        }
+
+        if (maxtb - lineLead > middlefollow) {
+                    middlefollow = maxtb - lineLead;
+        }
+
+        breakpoints.add(insertIndex,
+                        new LineBreakPosition(this,
+                                              knuthParagraphs.indexOf(par),
+                                              lastElementIndex ,
+                                              ratio, 0, indent,
+                                              lineLead + middlefollow,
+                                              lineLead));
+    }*/
+
+    
+    /**
+     * Phase 2 of Knuth algorithm: find optimal break points.
+     * @param alignment alignmenr of the paragraph
+     * @return a list of Knuth elements representing broken lines
+     */
+    private LinkedList findOptimalLineBreakingPoints(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());
+                }
+            }
+            lineLayoutsList.add(0, lineLayouts);
+        }
+        
+        
+        setFinished(true);
+    
+        //Post-process the line breaks found
+        return postProcessLineBreaks(alignment);
+    }
+
+    private LinkedList postProcessLineBreaks(int alignment) {
+    
+        LinkedList returnList = new LinkedList();
+        
+        for (int p = 0; p < knuthParagraphs.size(); p ++) {
+            // null penalty between paragraphs
+            if (p > 0
+                && !((BlockLevelLayoutManager) parentLM).mustKeepTogether()) {
+                returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+            }
+        
+            lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
+        
+            if (alignment == EN_JUSTIFY) {
+                /* justified vertical alignment (not in the XSL FO recommendation):
+                   create a multi-layout sequence whose elements will contain 
+                   a conventional Position */
+                Position returnPosition = new LeafPosition(this, p);
+                createElements(returnList, lineLayouts, returnPosition);
+            } else {
+                /* "normal" vertical alignment: create a sequence whose boxes
+                   represent effective lines, and contain LineBreakPositions */
+                Position returnPosition = new LeafPosition(this, p);
+                int startIndex = 0;
+                for (int i = 0;
+                        i < lineLayouts.getChosenLineCount();
+                        i++) {
+                    if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
+                        && i >= fobj.getOrphans()
+                        && i <= lineLayouts.getChosenLineCount() - fobj.getWidows()
+                        && returnList.size() > 0) {
+                        // null penalty allowing a page break between lines
+                        returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
+                    }
+                    int endIndex = ((LineBreakPosition) lineLayouts.getChosenPosition(i)).getLeafPos();
+                    // 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);
+                    while (elementIterator.nextIndex() <= endIndex) {
+                        KnuthElement element = (KnuthElement) elementIterator.next();
+                        if (element instanceof KnuthInlineBox
+                            && ((KnuthInlineBox) element).isAnchor()) {
+                            footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
+                        }
+                    }
+                    startIndex = endIndex + 1;
+                    returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
+                                                     footnoteList, lineLayouts.getChosenPosition(i), false));
+                }
+            }
+        }
+        
+        return returnList;
+    }
+
+
+    private void createElements(List list, LineLayoutPossibilities lineLayouts,
+                                Position elementPosition) {
+        /* number of normal, inner lines */
+        int nInnerLines = 0;
+        /* number of lines that can be used in order to fill more space */
+        int nOptionalLines = 0;
+        /* number of lines that can be used in order to fill more space
+           only if the paragraph is not parted */
+        int nConditionalOptionalLines = 0;
+        /* number of lines that can be omitted in order to fill less space */
+        int nEliminableLines = 0;
+        /* number of lines that can be omitted in order to fill less space
+           only if the paragraph is not parted */
+        int nConditionalEliminableLines = 0;
+        /* number of the first unbreakable lines */
+        int nFirstLines = fobj.getOrphans();
+        /* number of the last unbreakable lines */
+        int nLastLines = fobj.getWidows();
+        /* sub-sequence used to separate the elements representing different lines */
+        List breaker = new LinkedList();
+
+        /* comment out the next lines in order to test particular situations */
+        if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMinLineCount()) {
+            nInnerLines = lineLayouts.getMinLineCount() - (fobj.getOrphans() + fobj.getWidows());
+            nOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
+            nEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
+        } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getOptLineCount()) {
+            nOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
+            nEliminableLines = lineLayouts.getOptLineCount() - (fobj.getOrphans() + fobj.getWidows());
+            nConditionalEliminableLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getMinLineCount();
+        } else if (fobj.getOrphans() + fobj.getWidows() <= lineLayouts.getMaxLineCount()) {
+            nOptionalLines = lineLayouts.getMaxLineCount() - (fobj.getOrphans() + fobj.getWidows());
+            nConditionalOptionalLines = (fobj.getOrphans() + fobj.getWidows()) - lineLayouts.getOptLineCount();
+            nConditionalEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
+            nFirstLines -= nConditionalOptionalLines;
+        } else {
+            nConditionalOptionalLines = lineLayouts.getMaxLineCount() - lineLayouts.getOptLineCount();
+            nConditionalEliminableLines = lineLayouts.getOptLineCount() - lineLayouts.getMinLineCount();
+            nFirstLines = lineLayouts.getOptLineCount();
+            nLastLines = 0;
+        }
+        /* comment out the previous lines in order to test particular situations */
+
+        /* use these lines to test particular situations
+        nInnerLines = 0;
+        nOptionalLines = 1;
+        nConditionalOptionalLines = 2;
+        nEliminableLines = 0;
+        nConditionalEliminableLines = 0;
+        nFirstLines = 1;
+        nLastLines = 3;
+        */
+
+        if (nLastLines != 0
+            && (nConditionalOptionalLines > 0 || nConditionalEliminableLines > 0)) {
+            breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+            breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight,
+                                        -nConditionalEliminableLines * constantLineHeight,
+                                        LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+            breaker.add(new KnuthPenalty(nConditionalOptionalLines * constantLineHeight,
+                                           0, false, elementPosition, false));
+            breaker.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
+                                        nConditionalEliminableLines * constantLineHeight,
+                                        LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+        } else if (nLastLines != 0) {
+            breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false));
+        }
+
+        //System.out.println("first=" + nFirstLines + " inner=" + nInnerLines
+        //                   + " optional=" + nOptionalLines + " eliminable=" + nEliminableLines
+        //                   + " last=" + nLastLines
+        //                   + " (condOpt=" + nConditionalOptionalLines + " condEl=" + nConditionalEliminableLines + ")");
+
+        // creation of the elements:
+        // first group of lines
+        list.add(new KnuthBox(nFirstLines * constantLineHeight, elementPosition,
+                              (nLastLines == 0
+                               && nConditionalOptionalLines == 0
+                               && nConditionalEliminableLines == 0 ? true : false)));
+        if (nConditionalOptionalLines > 0
+            || nConditionalEliminableLines > 0) {
+            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+            list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
+                                   nConditionalEliminableLines * constantLineHeight,
+                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+            list.add(new KnuthBox(0, elementPosition,
+                                  (nLastLines == 0 ? true : false)));
+        }
+
+        // optional lines
+        for (int i = 0; i < nOptionalLines; i++) {
+            list.addAll(breaker);
+            list.add(new KnuthBox(0, elementPosition, false));
+            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+            list.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+            list.add(new KnuthBox(0, elementPosition, false));
+        }
+
+        // eliminable lines
+        for (int i = 0; i < nEliminableLines; i++) {
+            list.addAll(breaker);
+            list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
+            list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
+            list.add(new KnuthGlue(0, 0, 1 * constantLineHeight,
+                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+            list.add(new KnuthBox(0, elementPosition, false));
+        }
+
+        // inner lines
+        for (int i = 0; i < nInnerLines; i++) {
+            list.addAll(breaker);
+            list.add(new KnuthBox(1 * constantLineHeight, elementPosition, false));
+        }
+
+        // last group of lines
+        if (nLastLines > 0) {
+            list.addAll(breaker);
+            list.add(new KnuthBox(nLastLines * constantLineHeight,
+                                  elementPosition, true));
+        }
+    }
+
+    public boolean mustKeepTogether() {
+        return false;
+    }
+
+    public boolean mustKeepWithPrevious() {
+        return false;
+    }
+
+    public boolean mustKeepWithNext() {
+        return false;
+    }
+
+    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
+        LeafPosition pos = (LeafPosition)lastElement.getPosition();
+        int totalAdj = adj;
+        //if (lastElement.isPenalty()) {
+        //    totalAdj += lastElement.getW();
+        //}
+        //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight);
+        int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight + (adj > 0 ? - 0.4 : 0.4));
+        //System.out.println("   LLM> variazione calcolata = " + ((double) totalAdj / constantLineHeight) + " variazione applicata = " + lineNumberDifference);
+        lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(pos.getLeafPos());
+        lineNumberDifference = lineLayouts.applyLineCountAdjustment(lineNumberDifference);
+        return lineNumberDifference * constantLineHeight;
+    }
+
+    public void discardSpace(KnuthGlue spaceGlue) {
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList, int alignment) {
+        LinkedList returnList = new LinkedList();
+        for (int p = 0;
+             p < knuthParagraphs.size();
+             p ++) {
+            lineLayouts = (LineLayoutPossibilities)lineLayoutsList.get(p);
+            //System.out.println("demerits of the chosen layout: " + lineLayouts.getChosenDemerits());
+            for (int i = 0;
+                 i < lineLayouts.getChosenLineCount();
+                 i ++) {
+                if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
+                    && i >= fobj.getOrphans()
+                    && i <= lineLayouts.getChosenLineCount() - fobj.getWidows()) {
+                    // null penalty allowing a page break between lines
+                    returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
+                }
+                LineBreakPosition lbp = (LineBreakPosition) lineLayouts.getChosenPosition(i);
+                //System.out.println("LLM.getChangedKnuthElements> lineWidth= " + lbp.lineWidth + " difference= " + lbp.difference);
+                //System.out.println("                             shrink= " + lbp.availableShrink + " stretch= " + lbp.availableStretch);
+
+                //System.out.println("linewidth= " + lbp.lineWidth + " difference= " + lbp.difference + " indent= " + lbp.startIndent);
+                MinOptMax contentIPD;
+                if (alignment == EN_JUSTIFY) {
+                    contentIPD = new MinOptMax(
+                        lbp.lineWidth - lbp.difference - lbp.availableShrink, 
+                        lbp.lineWidth - lbp.difference, 
+                        lbp.lineWidth - lbp.difference + lbp.availableStretch);
+                } else if (alignment == EN_CENTER) {
+                    contentIPD = new MinOptMax(lbp.lineWidth - 2 * lbp.startIndent);
+                } else if (alignment == EN_END) {
+                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent);
+                } else {
+                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent);
+                }
+                returnList.add(new KnuthBlockBox(lbp.lineHeight,
+                                                 contentIPD,
+                                                 (lbp.ipdAdjust != 0 ? lbp.lineWidth - lbp.difference : 0),
+                                                 lbp, false));
+            }
+        }
+        return returnList;
+    }
+
+    /**
+     * find hyphenation points for every word int the current paragraph
+     * @ param currPar the paragraph whose words will be hyphenated
+     */
+    private void findHyphenationPoints(Paragraph currPar){
+        // hyphenate every word
+        ListIterator currParIterator
+            = currPar.listIterator(currPar.ignoreAtStart);
+        // list of TLM involved in hyphenation
+        LinkedList updateList = new LinkedList();
+        KnuthElement firstElement = null;
+        KnuthElement nextElement = null;
+        // current InlineLevelLayoutManager
+        InlineLevelLayoutManager currLM = null;
+        // number of KnuthBox elements containing word fragments
+        int boxCount;
+        // number of auxiliary KnuthElements between KnuthBoxes
+        int auxCount;
+        StringBuffer sbChars = null;
+
+        // find all hyphenation points
+        while (currParIterator.hasNext()) {
+            firstElement = (KnuthElement) currParIterator.next();
+            // 
+            if (firstElement.getLayoutManager() != currLM) {
+                currLM = (InlineLevelLayoutManager) firstElement.getLayoutManager();
+                if (currLM != null) { 
+                    updateList.add(new Update(currLM, currParIterator.previousIndex()));
+                } else {
+                    break;
+                }
+            }
+
+            // collect word fragments, ignoring auxiliary elements;
+            // each word fragment was created by a different TextLM
+            if (firstElement.isBox() && !firstElement.isAuxiliary()) {
+                boxCount = 1;
+                auxCount = 0;
+                sbChars = new StringBuffer();
+                currLM.getWordChars(sbChars, firstElement.getPosition());
+                // look if next elements are boxes too
+                while (currParIterator.hasNext()) {
+                    nextElement = (KnuthElement) currParIterator.next();
+                    if (nextElement.isBox() && !nextElement.isAuxiliary()) {
+                        // a non-auxiliary KnuthBox: append word chars
+                        if (currLM != nextElement.getLayoutManager()) {
+                            currLM = (InlineLevelLayoutManager) nextElement.getLayoutManager();
+                            updateList.add(new Update(currLM, currParIterator.previousIndex()));
+                        }
+                        // append text to recreate the whole word
+                        boxCount ++;
+                        currLM.getWordChars(sbChars, nextElement.getPosition());
+                    } else if (!nextElement.isAuxiliary()) {
+                        // a non-auxiliary non-box KnuthElement: stop
+                        // go back to the last box or auxiliary element
+                        currParIterator.previous(); 
+                        break;
+                    } else {
+                        // an auxiliary KnuthElement: simply ignore it
+                        auxCount ++;
+                    }
+                }
+                log.trace(" Word to hyphenate: " + sbChars.toString());
+                // find hyphenation points
+                HyphContext hc = getHyphenContext(sbChars);
+                // ask each LM to hyphenate its word fragment
+                if (hc != null) {
+                    KnuthElement element = null;
+                    for (int i = 0; i < (boxCount + auxCount); i++) {
+                        currParIterator.previous();
+                    }
+                    for (int i = 0; i < (boxCount + auxCount); i++) {
+                        element = (KnuthElement) currParIterator.next();
+                        if (element.isBox() && !element.isAuxiliary()) {
+                            ((InlineLevelLayoutManager)
+                             element.getLayoutManager()).hyphenate(element.getPosition(), hc);
+                        } else {
+                            // nothing to do, element is an auxiliary KnuthElement
+                        }
+                    }
+                }
+            }
+        }
+
+        // create iterator for the updateList
+        ListIterator updateListIterator = updateList.listIterator();
+        Update currUpdate = null;
+        //int iPreservedElements = 0;
+        int iAddedElements = 0;
+        //int iRemovedElements = 0;
+
+        while (updateListIterator.hasNext()) {
+            // ask the LMs to apply the changes and return 
+            // the new KnuthElements to replace the old ones
+            currUpdate = (Update) updateListIterator.next();
+            int fromIndex = currUpdate.iFirstIndex;
+            int toIndex;
+            if (updateListIterator.hasNext()) {
+                Update nextUpdate = (Update) updateListIterator.next();
+                toIndex = nextUpdate.iFirstIndex;
+                updateListIterator.previous();
+            } else {
+                // maybe this is not always correct!
+                toIndex = currPar.size() - currPar.ignoreAtEnd
+                    - iAddedElements;
+            }
+
+            // applyChanges() returns true if the LM modifies its data,
+            // so it must return new KnuthElements to replace the old ones
+            if (((InlineLevelLayoutManager) currUpdate.inlineLM)
+                .applyChanges(currPar.subList(fromIndex + iAddedElements,
+                                              toIndex + iAddedElements))) {
+                // insert the new KnuthElements
+                LinkedList newElements = null;
+                newElements
+                    = currUpdate.inlineLM.getChangedKnuthElements
+                    (currPar.subList(fromIndex + iAddedElements,
+                                     toIndex + iAddedElements),
+                     /*flaggedPenalty,*/ effectiveAlignment);
+                // remove the old elements
+                currPar.subList(fromIndex + iAddedElements,
+                                toIndex + iAddedElements).clear();
+                // insert the new elements
+                currPar.addAll(fromIndex + iAddedElements, newElements);
+                iAddedElements += newElements.size() - (toIndex - fromIndex);
+            }
+        }
+        updateListIterator = null;
+        updateList.clear();
+    }
+
+    /** Line area is always considered to act as a fence. */
+    protected boolean hasLeadingFence(boolean bNotFirst) {
+        return true;
+    }
+
+    /** Line area is always considered to act as a fence. */
+    protected boolean hasTrailingFence(boolean bNotLast) {
+        return true;
+    }
+
+    private HyphContext getHyphenContext(StringBuffer sbChars) {
+        // Find all hyphenation points in this word
+        // (get in an array of offsets)
+        // hyphProps are from the block level?.
+        // Note that according to the spec,
+        // they also "apply to" fo:character.
+        // I don't know what that means, since
+        // if we change language in the middle of a "word",
+        // the effect would seem quite strange!
+        // Or perhaps in that case, we say that it's several words.
+        // We probably should bring the hyphenation props up from the actual
+        // TextLM which generate the hyphenation buffer,
+        // since these properties inherit and could be specified
+        // on an inline or wrapper below the block level.
+        Hyphenation hyph
+            = Hyphenator.hyphenate(hyphProps.language,
+                                   hyphProps.country, sbChars.toString(),
+                                   hyphProps.hyphenationRemainCharacterCount,
+                                   hyphProps.hyphenationPushCharacterCount);
+        // They hyph structure contains the information we need
+        // Now start from prev: reset to that position, ask that LM to get
+        // a Position for the first hyphenation offset. If the offset isn't in
+        // its characters, it returns null,
+        // but must tell how many chars it had.
+        // Keep looking at currentBP using next hyphenation point until the
+        // returned size is greater than the available size
+        // or no more hyphenation points remain. Choose the best break.
+        if (hyph != null) {
+            return new HyphContext(hyph.getHyphenationPoints());
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Reset the positions to the given position.
+     *
+     * @param resetPos the position to reset to
+     */
+    public void resetPosition(Position resetPos) {
+        if (resetPos == null) {
+            setFinished(false);
+            iReturnedLBP = 0;
+        } else {
+            if (isFinished()) {
+                // if isFinished is true, iReturned LBP == breakpoints.size()
+                // and breakpoints.get(iReturnedLBP) would generate
+                // an IndexOutOfBoundException
+                setFinished(false);
+                iReturnedLBP--;
+            }
+            while ((LineBreakPosition) lineLayouts.getChosenPosition(iReturnedLBP)
+                   != (LineBreakPosition) resetPos) {
+                iReturnedLBP--;
+            }
+            iReturnedLBP++;
+        }
+    }
+
+    /**
+     * Add the areas with the break points.
+     *
+     * @param parentIter the iterator of break positions
+     * @param context the context for adding areas
+     */
+    public void addAreas(PositionIterator parentIter,
+                         LayoutContext context) {
+        LayoutManager childLM;
+        LayoutContext lc = new LayoutContext(0);
+        int iCurrParIndex;
+        while (parentIter.hasNext()) {
+            Position pos = (Position) parentIter.next();
+            if (pos instanceof LineBreakPosition) {
+                ListIterator paragraphIterator = null;
+                KnuthElement tempElement = null;
+                // the TLM which created the last KnuthElement in this line
+                LayoutManager lastLM = null;
+    
+                LineBreakPosition lbp = (LineBreakPosition) pos;
+                LineArea lineArea = new LineArea();
+                lineArea.setStartIndent(lbp.startIndent);
+                lineArea.setBPD(lbp.lineHeight);
+                lc.setBaseline(lbp.baseline);
+                lc.setLineHeight(lbp.lineHeight);
+                lc.setMiddleShift(middleShift);
+                lc.setTopShift(lbp.topShift);
+                lc.setBottomShift(lbp.bottomShift);
+
+                iCurrParIndex = lbp.iParIndex;
+                Paragraph currPar = (Paragraph) 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))
+                    ? currPar.ignoreAtEnd : 0;
+    
+                // ignore the last element in the line if it is a KnuthGlue object
+                paragraphIterator = currPar.listIterator(iEndElement);
+                tempElement = (KnuthElement) paragraphIterator.next();
+                if (tempElement.isGlue()) {
+                    iEndElement --;
+                    // this returns the same KnuthElement
+                    paragraphIterator.previous();
+                    tempElement = (KnuthElement) paragraphIterator.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();
+                    iStartElement ++;
+                }
+    
+                // Add the inline areas to lineArea
+                PositionIterator inlinePosIter
+                    = new KnuthPossPosIter(currPar, iStartElement,
+                                           iEndElement + 1);
+    
+                iStartElement = lbp.getLeafPos() + 1;
+                if (iStartElement == currPar.size()) {
+                    // advance to next paragraph
+                    iStartElement = 0;
+                }
+    
+                lc.setSpaceAdjust(lbp.dAdjust);
+                lc.setIPDAdjust(lbp.ipdAdjust);
+                lc.setLeadingSpace(new SpaceSpecifier(true));
+                lc.setTrailingSpace(new SpaceSpecifier(false));
+                lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
+
+                /* extension (not in the XSL FO recommendation): if the left and right margins
+                   have been optimized, recompute indents and / or adjust ratio, according
+                   to the paragraph horizontal alignment */
+                if (false && bTextAlignment == EN_JUSTIFY) {
+                    // re-compute space adjust ratio
+                    int updatedDifference = context.getStackLimit().opt - lbp.lineWidth + lbp.difference;
+                    double updatedRatio = 0.0;
+                    if (updatedDifference > 0) {
+                        updatedRatio = (float) updatedDifference / lbp.availableStretch;
+                    } else if (updatedDifference < 0) {
+                        updatedRatio = (float) updatedDifference / lbp.availableShrink;
+                    }
+                    lc.setIPDAdjust(updatedRatio);
+                    //System.out.println("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
+                    //System.out.println("              old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
+                } else if (false && bTextAlignment == EN_CENTER) {
+                    // re-compute indent
+                    int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth) / 2;
+                    lineArea.setStartIndent(updatedIndent);
+                } else if (false && bTextAlignment == EN_END) {
+                    // re-compute indent
+                    int updatedIndent = lbp.startIndent + (context.getStackLimit().opt - lbp.lineWidth);
+                    lineArea.setStartIndent(updatedIndent);
+                }
+
+                setCurrentArea(lineArea);
+                setChildContext(lc);
+                while ((childLM = inlinePosIter.getNextChildLM()) != null) {
+                    lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
+                    childLM.addAreas(inlinePosIter, lc);
+                    lc.setLeadingSpace(lc.getTrailingSpace());
+                    lc.setTrailingSpace(new SpaceSpecifier(false));
+                }
+                
+                // when can this be null?
+                // if display-align is distribute, add space after 
+                if (context.getSpaceAfter() > 0
+                    && (!context.isLastArea() || parentIter.hasNext())) {
+                    lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
+                }
+                parentLM.addChildArea(lineArea);
+            } else {
+                // pos was the Position inside a penalty item, nothing to do
+            }
+        }
+        setCurrentArea(null); // ?? necessary
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutPossibilities.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutPossibilities.java
new file mode 100644 (file)
index 0000000..d7f41ef
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2004-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.layoutmgr.inline;
+
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.fop.layoutmgr.Position;
+
+public class LineLayoutPossibilities {
+
+    /** logger instance */
+    protected static Log log = LogFactory.getLog(LineLayoutPossibilities.class);
+    
+    private class Possibility {
+        private int lineCount;
+        private double demerits;
+        private List breakPositions;
+
+        private Possibility(int lc, double dem) {
+            lineCount = lc;
+            demerits = dem;
+            breakPositions = new java.util.ArrayList(lc);
+        }
+
+        private int getLineCount() {
+            return lineCount;
+        }
+
+        private double getDemerits() {
+            return demerits;
+        }
+
+        private void addBreakPosition(Position pos) {
+            // Positions are always added with index 0 because 
+            // they are created backward, from the last one to 
+            // the first one
+            breakPositions.add(0, pos);
+        }
+
+        private Position getBreakPosition(int i) {
+            return (Position)breakPositions.get(i);
+        }
+    }
+
+    private List possibilitiesList;
+    private List savedPossibilities;
+    private int minimumIndex;
+    private int optimumIndex;
+    private int maximumIndex;
+    private int chosenIndex;
+    private int savedOptLineCount;
+
+    public LineLayoutPossibilities() {
+        possibilitiesList = new java.util.ArrayList();
+        savedPossibilities = new java.util.ArrayList();
+        optimumIndex = -1;
+    }
+    public void addPossibility(int ln, double dem) {
+        possibilitiesList.add(new Possibility(ln, dem));
+        if (possibilitiesList.size() == 1) {
+            // first Possibility added
+            minimumIndex = 0;
+            optimumIndex = 0;
+            maximumIndex = 0;
+            chosenIndex = 0;
+        } else {
+            if (dem < ((Possibility)possibilitiesList.get(optimumIndex)).getDemerits()) {
+                optimumIndex = possibilitiesList.size() - 1;
+                chosenIndex = optimumIndex;
+            }
+            if (ln < ((Possibility)possibilitiesList.get(minimumIndex)).getLineCount()) {
+                minimumIndex = possibilitiesList.size() - 1;
+            }
+            if (ln > ((Possibility)possibilitiesList.get(maximumIndex)).getLineCount()) {
+                maximumIndex = possibilitiesList.size() - 1;
+            }
+        }
+    }
+
+    /* save in a different array the computed Possibilities,
+     * so possibilitiesList is ready to store different Possibilities
+     */
+    public void savePossibilities(boolean bSaveOptLineCount) {
+        if (bSaveOptLineCount) {
+            savedOptLineCount = getOptLineCount();
+        } else {
+            savedOptLineCount = 0;
+        }
+        savedPossibilities = possibilitiesList;
+        possibilitiesList = new java.util.ArrayList();
+    }
+
+    /* replace the Possibilities stored in possibilitiesList with
+     * the ones stored in savedPossibilities and having the same line number
+     */
+    public void restorePossibilities() {
+        int index = 0;
+        while (savedPossibilities.size() > 0) {
+            Possibility restoredPossibility = (Possibility) savedPossibilities.remove(0);
+            if (restoredPossibility.getLineCount() < getMinLineCount()) {
+                // if the line number of restoredPossibility is less than the minimum one,
+                // add restoredPossibility at the beginning of the list
+                possibilitiesList.add(0, restoredPossibility);
+                // update minimumIndex
+                minimumIndex = 0;
+                // shift the other indexes;
+                optimumIndex ++;
+                maximumIndex ++;
+                chosenIndex ++;
+            } else if (restoredPossibility.getLineCount() > getMaxLineCount()) {
+                // if the line number of restoredPossibility is greater than the maximum one,
+                // add restoredPossibility at the end of the list
+                possibilitiesList.add(possibilitiesList.size(), restoredPossibility);
+                // update maximumIndex
+                maximumIndex = possibilitiesList.size() - 1;
+                index = maximumIndex;
+            } else {
+                // find the index of the Possibility that will be replaced
+                while (index < maximumIndex
+                       && getLineCount(index) < restoredPossibility.getLineCount()) {
+                    index ++;
+                }
+                if (getLineCount(index) == restoredPossibility.getLineCount()) {
+                    possibilitiesList.set(index, restoredPossibility);
+                } else {
+                    // this should not happen
+                    log.error("LineLayoutPossibilities restorePossibilities(),"
+                        + " min= " + getMinLineCount() 
+                        + " max= " + getMaxLineCount() 
+                        + " restored= " + restoredPossibility.getLineCount());
+                    return;
+                }
+            }
+            // update optimumIndex and chosenIndex
+            if (savedOptLineCount == 0 && getDemerits(optimumIndex) > restoredPossibility.getDemerits()
+                || savedOptLineCount != 0 && restoredPossibility.getLineCount() == savedOptLineCount) {
+                optimumIndex = index;
+                chosenIndex = optimumIndex;
+            }
+        }
+/*LF*/  //System.out.println(">> minLineCount = " + getMinLineCount() + " optLineCount = " + getOptLineCount() + " maxLineCount() = " + getMaxLineCount());
+    }
+
+    public void addBreakPosition(Position pos, int i) {
+        ((Possibility)possibilitiesList.get(i)).addBreakPosition(pos);
+    }
+
+    public boolean canUseMoreLines() {
+        return (getOptLineCount() < getMaxLineCount());
+    }
+
+    public boolean canUseLessLines() {
+        return (getMinLineCount() < getOptLineCount());
+    }
+
+    public int getMinLineCount() {
+        return getLineCount(minimumIndex);
+    }
+
+    public int getOptLineCount() {
+        return getLineCount(optimumIndex);
+    }
+
+    public int getMaxLineCount() {
+        return getLineCount(maximumIndex);
+    }
+
+    public int getChosenLineCount() {
+        return getLineCount(chosenIndex);
+    }
+
+    public int getLineCount(int i) {
+        return ((Possibility)possibilitiesList.get(i)).getLineCount();
+    }
+
+    public double getChosenDemerits() {
+        return getDemerits(chosenIndex);
+    }
+
+    public double getDemerits(int i) {
+        return ((Possibility)possibilitiesList.get(i)).getDemerits();
+    }
+
+    public int getPossibilitiesNumber() {
+        return possibilitiesList.size();
+    }
+
+    public Position getChosenPosition(int i) {
+        return ((Possibility)possibilitiesList.get(chosenIndex)).getBreakPosition(i);
+    }
+
+    public int applyLineCountAdjustment(int adj) {
+        if (adj >= (getMinLineCount() - getChosenLineCount())
+            && adj <= (getMaxLineCount() - getChosenLineCount())
+            && getLineCount(chosenIndex + adj) == getChosenLineCount() + adj) {
+            chosenIndex += adj;
+            log.debug("chosenLineCount= " + (getChosenLineCount() - adj) + " adjustment= " + adj
+                               + " => chosenLineCount= " + getLineCount(chosenIndex));
+            return adj;
+        } else {
+            // this should not happen!
+            log.warn("Cannot apply the desired line count adjustment.");
+            return 0;
+        }
+    }
+
+    public void printAll() {
+        System.out.println("++++++++++");
+        System.out.println(" " + possibilitiesList.size() + " possibility':");
+        for (int i = 0; i < possibilitiesList.size(); i ++) {
+            System.out.println("   " + ((Possibility)possibilitiesList.get(i)).getLineCount()
+                               + (i == optimumIndex ? " *" : "")
+                               + (i == minimumIndex ? " -" : "")
+                               + (i == maximumIndex ? " +" : ""));
+        }
+        System.out.println("++++++++++");
+    }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLayoutManager.java
new file mode 100644 (file)
index 0000000..3fe902b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.fo.flow.PageNumberCitation;
+import org.apache.fop.area.PageViewport;
+import org.apache.fop.area.Resolvable;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.UnresolvedPageNumber;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.layoutmgr.TraitSetter;
+
+/**
+ * LayoutManager for the fo:page-number-citation formatting object
+ */
+public class PageNumberCitationLayoutManager extends LeafNodeLayoutManager {
+
+    private PageNumberCitation fobj;
+    private Font font;
+    
+    // whether the page referred to by the citation has been resolved yet
+    private boolean resolved = false;
+    
+    /**
+     * Constructor
+     *
+     * @param node the formatting object that creates this area
+     * @todo better retrieval of font info
+     */
+    public PageNumberCitationLayoutManager(PageNumberCitation node) {
+        super(node);
+        fobj = node;
+        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
+    }
+
+    public InlineArea get(LayoutContext context) {
+        curArea = getPageNumberCitationInlineArea(parentLM);
+        return curArea;
+    }
+    
+    public void addAreas(PositionIterator posIter, LayoutContext context) {
+        super.addAreas(posIter, context);
+        if (!resolved) {
+            getPSLM().addUnresolvedArea(fobj.getRefId(), (Resolvable) curArea);
+        }
+    }
+    
+    /** @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#getLead() */
+    public int getLead() {
+        return font.getAscender();
+    }
+
+    protected void offsetArea(InlineArea area, LayoutContext context) {
+        area.setOffset(context.getBaseline());
+    }
+
+    /**
+     * if id can be resolved then simply return a word, otherwise
+     * return a resolvable area
+     */
+    private InlineArea getPageNumberCitationInlineArea(LayoutManager parentLM) {
+        PageViewport page = getPSLM().getFirstPVWithID(fobj.getRefId());
+        InlineArea inline = null;
+        if (page != null) {
+            String str = page.getPageNumberString();
+            // get page string from parent, build area
+            TextArea text = new TextArea();
+            inline = text;
+            int width = getStringWidth(str);
+            text.setTextArea(str);
+            inline.setIPD(width);
+            
+            resolved = true;
+        } else {
+            resolved = false;
+            inline = new UnresolvedPageNumber(fobj.getRefId());
+            String str = "MMM"; // reserve three spaces for page number
+            int width = getStringWidth(str);
+            inline.setIPD(width);
+            
+        }
+        inline.setBPD(font.getAscender() - font.getDescender());
+        inline.setOffset(font.getAscender());
+        inline.addTrait(Trait.FONT_NAME, font.getFontName());
+        inline.addTrait(Trait.FONT_SIZE, new Integer(font.getFontSize()));
+        TraitSetter.addTextDecoration(inline, fobj.getTextDecoration());
+        
+        return inline;
+    }
+    
+    /**
+     * @param str string to be measured
+     * @return width (in millipoints ??) of the string
+     */
+    private int getStringWidth(String str) {
+        int width = 0;
+        for (int count = 0; count < str.length(); count++) {
+            width += font.getCharWidth(str.charAt(count));
+        }
+        return width;
+    }
+    
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java
new file mode 100644 (file)
index 0000000..409efa3
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import org.apache.fop.fo.flow.PageNumber;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.area.Trait;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.TraitSetter;
+
+/**
+ * LayoutManager for the fo:page-number formatting object
+ */
+public class PageNumberLayoutManager extends LeafNodeLayoutManager {
+    
+    private PageNumber fobj;
+    private Font font;
+    
+    /**
+     * Constructor
+     *
+     * @param node the fo:page-number formatting object that creates the area
+     * @todo better null checking of node, font
+     */
+    public PageNumberLayoutManager(PageNumber node) {
+        super(node);
+        fobj = node;
+        font = fobj.getCommonFont().getFontState(fobj.getFOEventHandler().getFontInfo());
+    }
+
+    public InlineArea get(LayoutContext context) {
+        // get page string from parent, build area
+        TextArea inline = new TextArea();
+        String str = getCurrentPV().getPageNumberString();
+        int width = 0;
+        for (int count = 0; count < str.length(); count++) {
+            width += font.getCharWidth(str.charAt(count));
+        }
+        inline.setTextArea(str);
+        inline.setIPD(width);
+        inline.setBPD(font.getAscender() - font.getDescender());
+        inline.setOffset(font.getAscender());
+        inline.addTrait(Trait.FONT_NAME, font.getFontName());
+        inline.addTrait(Trait.FONT_SIZE,
+                        new Integer(font.getFontSize()));
+
+        TraitSetter.addTextDecoration(inline, fobj.getTextDecoration());
+
+        return inline;
+    }
+    
+    
+    /** @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#getLead() */
+    public int getLead() {
+        return font.getAscender();
+    }
+    
+    protected void offsetArea(InlineArea area, LayoutContext context) {
+        area.setOffset(context.getBaseline());
+    }
+    
+    protected InlineArea getEffectiveArea() {
+        TextArea baseArea = (TextArea)curArea;
+        //TODO Maybe replace that with a clone() call or better, a copy constructor
+        //TODO or even better: delay area creation until addAreas() stage
+        //TextArea is cloned because the LM is reused in static areas and the area can't be.
+        TextArea ta = new TextArea();
+        ta.setIPD(baseArea.getIPD());
+        ta.setBPD(baseArea.getBPD());
+        ta.setOffset(baseArea.getOffset());
+        ta.addTrait(Trait.FONT_NAME, font.getFontName()); //only to initialize the trait map
+        ta.getTraits().putAll(baseArea.getTraits());
+        updateContent(ta);
+        return ta;
+    }
+    
+    private void updateContent(TextArea area) {
+        area.setTextArea(getCurrentPV().getPageNumberString());
+    }
+    
+    protected void addId() {
+        getPSLM().addIDToPage(fobj.getId());
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
new file mode 100644 (file)
index 0000000..1a33d19
--- /dev/null
@@ -0,0 +1,871 @@
+/*
+ * Copyright 1999-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.layoutmgr.inline;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.LinkedList;
+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.KnuthBox;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LeafPosition;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.traits.SpaceVal;
+import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.InlineArea;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.traits.MinOptMax;
+
+/**
+ * LayoutManager for text (a sequence of characters) which generates one
+ * or more inline areas.
+ */
+public class TextLayoutManager extends LeafNodeLayoutManager {
+
+    /**
+     * Store information about each potential text area.
+     * Index of character which ends the area, IPD of area, including
+     * any word-space and letter-space.
+     * Number of word-spaces?
+     */
+    private class AreaInfo {
+        private short iStartIndex;
+        private short iBreakIndex;
+        private short iWScount;
+        private short iLScount;
+        private MinOptMax ipdArea;
+        private boolean bHyphenated;
+        public AreaInfo(short iSIndex, short iBIndex, short iWS, short iLS,
+                        MinOptMax ipd, boolean bHyph) {
+            iStartIndex = iSIndex;
+            iBreakIndex = iBIndex;
+            iWScount = iWS;
+            iLScount = iLS;
+            ipdArea = ipd;
+            bHyphenated = bHyph;
+        }
+    }
+
+    // this class stores information about changes in vecAreaInfo
+    // which are not yet applied
+    private class PendingChange {
+        public AreaInfo ai;
+        public int index;
+
+        public PendingChange(AreaInfo ai, int index) {
+            this.ai = ai;
+            this.index = index;
+        }
+    }
+
+    // Hold all possible breaks for the text in this LM's FO.
+    private ArrayList vecAreaInfo;
+
+    /** Non-space characters on which we can end a line. */
+    private static final String BREAK_CHARS = "-/" ;
+
+    private FOText foText;
+    private char[] textArray;
+
+    private static final char NEWLINE = '\n';
+    private static final char SPACE = '\u0020'; // Normal space
+    private static final char NBSPACE = '\u00A0'; // Non-breaking space
+    private static final char LINEBREAK = '\u2028';
+    private static final char ZERO_WIDTH_SPACE = '\u200B';
+    // byte order mark
+    private static final char ZERO_WIDTH_NOBREAK_SPACE = '\uFEFF';
+
+    /** Start index of first character in this parent Area */
+    private short iAreaStart = 0;
+    /** Start index of next TextArea */
+    private short iNextStart = 0;
+    /** Size since last makeArea call, except for last break */
+    private MinOptMax ipdTotal;
+    /** Size including last break possibility returned */
+    // private MinOptMax nextIPD = new MinOptMax(0);
+    /** size of a space character (U+0020) glyph in current font */
+    private int spaceCharIPD;
+    private MinOptMax wordSpaceIPD;
+    private MinOptMax letterSpaceIPD;
+    /** size of the hyphen character glyph in current font */
+    private int hyphIPD;
+    /** 1/2 of word-spacing value */
+    private SpaceVal halfWS;
+    /** Number of space characters after previous possible break position. */
+    private int iNbSpacesPending;
+    private Font fs;
+
+    private boolean bChanged = false;
+    private int iReturnedIndex = 0;
+    private short iThisStart = 0;
+    private short iTempStart = 0;
+    private LinkedList changeList = null;
+
+    private int textHeight;
+    private int lead = 0;
+    private int total = 0;
+    private int middle = 0;
+    private int verticalAlignment = EN_BASELINE;
+
+    /**
+     * Create a Text layout manager.
+     *
+     * @param node The FOText object to be rendered
+     */
+    public TextLayoutManager(FOText node) {
+        super();
+        foText = node;
+        
+        textArray = new char[node.endIndex - node.startIndex];
+        System.arraycopy(node.ca, node.startIndex, textArray, 0,
+            node.endIndex - node.startIndex);
+
+        vecAreaInfo = new java.util.ArrayList();
+
+        fs = foText.getCommonFont().getFontState(foText.getFOEventHandler().getFontInfo());
+        
+        // With CID fonts, space isn't neccesary currentFontState.width(32)
+        spaceCharIPD = fs.getCharWidth(' ');
+        // Use hyphenationChar property
+        hyphIPD = fs.getCharWidth(foText.getCommonHyphenation().hyphenationCharacter);
+        // Make half-space: <space> on either side of a word-space)
+        SpaceVal ls = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
+        SpaceVal ws = SpaceVal.makeWordSpacing(foText.getWordSpacing(), ls, fs);
+        halfWS = new SpaceVal(MinOptMax.multiply(ws.getSpace(), 0.5),
+                ws.isConditional(), ws.isForcing(), ws.getPrecedence());
+
+        // letter space applies only to consecutive non-space characters,
+        // while word space applies to space characters;
+        // i.e. the spaces in the string "A SIMPLE TEST" are:
+        //      A<<ws>>S<ls>I<ls>M<ls>P<ls>L<ls>E<<ws>>T<ls>E<ls>S<ls>T
+        // there is no letter space after the last character of a word,
+        // nor after a space character
+
+        // set letter space and word space dimension;
+        // the default value "normal" was converted into a MinOptMax value
+        // in the SpaceVal.makeWordSpacing() method
+        letterSpaceIPD = ls.getSpace();
+        wordSpaceIPD = MinOptMax.add(new MinOptMax(spaceCharIPD), ws.getSpace());
+
+        // set text height
+        textHeight = fs.getAscender()
+                     - fs.getDescender();
+
+        // if the text node is son of an inline, set vertical align
+        if (foText.getParent() instanceof Inline) {
+            setAlignment(((Inline) foText.getParent()).getVerticalAlign());
+        }
+        switch (verticalAlignment) {
+            case EN_MIDDLE  : middle = textHeight / 2 ;
+                                         break;
+            case EN_TOP     : // fall through
+            case EN_BOTTOM  : total = textHeight;
+                                         break;
+            case EN_BASELINE: // fall through
+            default                    : lead = fs.getAscender();
+                                         total = textHeight;
+                                         break;
+        }
+    }
+
+    /**
+     * Reset position for returning next BreakPossibility.
+     *
+     * @param prevPos the position to reset to
+     */
+    public void resetPosition(Position prevPos) {
+        if (prevPos != null) {
+            // ASSERT (prevPos.getLM() == this)
+            if (prevPos.getLM() != this) {
+                log.error("TextLayoutManager.resetPosition: "
+                          + "LM mismatch!!!");
+            }
+            LeafPosition tbp = (LeafPosition) prevPos;
+            AreaInfo ai =
+              (AreaInfo) vecAreaInfo.get(tbp.getLeafPos());
+            if (ai.iBreakIndex != iNextStart) {
+                iNextStart = ai.iBreakIndex;
+                vecAreaInfo.ensureCapacity(tbp.getLeafPos() + 1);
+                // TODO: reset or recalculate total IPD = sum of all word IPD
+                // up to the break position
+                ipdTotal = ai.ipdArea;
+                setFinished(false);
+            }
+        } else {
+            // Reset to beginning!
+            vecAreaInfo.clear();
+            iNextStart = 0;
+            setFinished(false);
+        }
+    }
+
+    // TODO: see if we can use normal getNextBreakPoss for this with
+    // extra hyphenation information in LayoutContext
+    private boolean getHyphenIPD(HyphContext hc, MinOptMax hyphIPD) {
+        // Skip leading word-space before calculating count?
+        boolean bCanHyphenate = true;
+        int iStopIndex = iNextStart + hc.getNextHyphPoint();
+
+        if (textArray.length < iStopIndex) {
+            iStopIndex = textArray.length;
+            bCanHyphenate = false;
+        }
+        hc.updateOffset(iStopIndex - iNextStart);
+
+        for (; iNextStart < iStopIndex; iNextStart++) {
+            char c = textArray[iNextStart];
+            hyphIPD.opt += fs.getCharWidth(c);
+            // letter-space?
+        }
+        // Need to include hyphen size too, but don't count it in the
+        // stored running total, since it would be double counted
+        // with later hyphenation points
+        return bCanHyphenate;
+    }
+
+    /**
+     * Generate and add areas to parent area.
+     * This can either generate an area for each TextArea and each space, or
+     * an area containing all text with a parameter controlling the size of
+     * the word space. The latter is most efficient for PDF generation.
+     * Set size of each area.
+     * @param posIter Iterator over Position information returned
+     * by this LayoutManager.
+     * @param context LayoutContext for adjustments
+     */
+    public void addAreas(PositionIterator posIter, LayoutContext context) {
+
+        // Add word areas
+        AreaInfo ai = null;
+        int iStart = -1;
+        int iWScount = 0;
+        int iLScount = 0;
+        MinOptMax realWidth = new MinOptMax(0);
+
+        /* On first area created, add any leading space.
+         * Calculate word-space stretch value.
+         */
+        while (posIter.hasNext()) {
+            LeafPosition tbpNext = (LeafPosition) posIter.next();
+            //
+            if (tbpNext.getLeafPos() != -1) {
+                ai = (AreaInfo) vecAreaInfo.get(tbpNext.getLeafPos());
+                if (iStart == -1) {
+                    iStart = ai.iStartIndex;
+                }
+                iWScount += ai.iWScount;
+                iLScount += ai.iLScount;
+                realWidth.add(ai.ipdArea);
+            }
+        }
+        if (ai == null) {
+            return;
+        }
+
+        // Make an area containing all characters between start and end.
+        InlineArea word = null;
+        int adjust = 0;
+        
+        // ignore newline character
+        if (textArray[ai.iBreakIndex - 1] == NEWLINE) {
+            adjust = 1;
+        }
+        String str = new String(textArray, iStart,
+                                ai.iBreakIndex - iStart - adjust);
+
+        // add hyphenation character if the last word is hyphenated
+        if (context.isLastArea() && ai.bHyphenated) {
+            str += foText.getCommonHyphenation().hyphenationCharacter;
+            realWidth.add(new MinOptMax(hyphIPD));
+        }
+
+        // Calculate adjustments
+        int iDifference = 0;
+        int iTotalAdjust = 0;
+        int iWordSpaceDim = wordSpaceIPD.opt;
+        int iLetterSpaceDim = letterSpaceIPD.opt;
+        double dIPDAdjust = context.getIPDAdjust();
+        double dSpaceAdjust = context.getSpaceAdjust(); // not used
+
+        // calculate total difference between real and available width
+        if (dIPDAdjust > 0.0) {
+            iDifference = (int) ((double) (realWidth.max - realWidth.opt)
+                                * dIPDAdjust);
+        } else {
+            iDifference = (int) ((double) (realWidth.opt - realWidth.min)
+                                * dIPDAdjust);
+        }
+        
+        // set letter space adjustment
+        if (dIPDAdjust > 0.0) {
+            iLetterSpaceDim
+                += (int) ((double) (letterSpaceIPD.max - letterSpaceIPD.opt)
+                         * dIPDAdjust);
+        } else  {
+            iLetterSpaceDim
+                += (int) ((double) (letterSpaceIPD.opt - letterSpaceIPD.min)
+                         * dIPDAdjust);
+        }
+        iTotalAdjust += (iLetterSpaceDim - letterSpaceIPD.opt) * iLScount;
+
+        // set word space adjustment
+        // 
+        if (iWScount > 0) {
+            iWordSpaceDim += (int) ((iDifference - iTotalAdjust) / iWScount);
+        } else {
+            // there are no word spaces in this area
+        }
+        iTotalAdjust += (iWordSpaceDim - wordSpaceIPD.opt) * iWScount;
+
+        TextArea t = createTextArea(str, realWidth.opt + iTotalAdjust,
+                                    context);
+
+        // iWordSpaceDim is computed in relation to wordSpaceIPD.opt
+        // but the renderer needs to know the adjustment in relation
+        // to the size of the space character in the current font;
+        // moreover, the pdf renderer adds the character spacing even to
+        // the last character of a word and to space characters: in order
+        // to avoid this, we must subtract the letter space width twice;
+        // the renderer will compute the space width as:
+        //   space width = 
+        //     = "normal" space width + letterSpaceAdjust + wordSpaceAdjust
+        //     = spaceCharIPD + letterSpaceAdjust +
+        //       + (iWordSpaceDim - spaceCharIPD -  2 * letterSpaceAdjust)
+        //     = iWordSpaceDim - letterSpaceAdjust
+        t.setTextLetterSpaceAdjust(iLetterSpaceDim);
+        t.setTextWordSpaceAdjust(iWordSpaceDim - spaceCharIPD
+                                 - 2 * t.getTextLetterSpaceAdjust());
+        
+        word = t;
+        if (word != null) {
+            parentLM.addChildArea(word);
+        }
+    }
+
+    /**
+     * Create an inline word area.
+     * This creates a TextArea and sets up the various attributes.
+     *
+     * @param str the string for the TextArea
+     * @param width the width that the TextArea uses
+     * @param base the baseline position
+     * @return the new word area
+     */
+    protected TextArea createTextArea(String str, int width, LayoutContext context) {
+        TextArea textArea = new TextArea();
+        textArea.setIPD(width);
+        textArea.setBPD(fs.getAscender() - fs.getDescender());
+        int bpd = textArea.getBPD();
+        switch (verticalAlignment) {
+            case EN_MIDDLE:
+                textArea.setOffset(context.getMiddleBaseline() + fs.getXHeight() / 2);
+            break;
+            case EN_TOP:
+                textArea.setOffset(context.getTopBaseline() + fs.getAscender());
+            break;
+            case EN_BOTTOM:
+                textArea.setOffset(context.getBottomBaseline() - bpd + fs.getAscender());
+            break;
+            case EN_BASELINE:
+            default:
+                textArea.setOffset(context.getBaseline());
+            break;
+        }
+
+        textArea.setTextArea(str);
+        textArea.addTrait(Trait.FONT_NAME, fs.getFontName());
+        textArea.addTrait(Trait.FONT_SIZE, new Integer(fs.getFontSize()));
+        textArea.addTrait(Trait.COLOR, foText.getColor());
+        
+        TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
+        
+        return textArea;
+    }
+
+    /**
+     * Set the alignment of the inline area.
+     * @param al the vertical alignment positioning
+     */
+    public void setAlignment(int al) {
+        verticalAlignment = al;
+    }
+
+    public LinkedList getNextKnuthElements(LayoutContext context,
+                                           int alignment) {
+        LinkedList returnList = new LinkedList();
+
+        while (iNextStart < textArray.length) {
+            if (textArray[iNextStart] == SPACE
+                || textArray[iNextStart] == NBSPACE) {
+                // normal, breaking space
+                // or non-breaking space
+                if (textArray[iNextStart] == NBSPACE) {
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, vecAreaInfo.size() - 1),
+                                          false));
+                }
+                switch (alignment) {
+                case EN_CENTER :
+                    vecAreaInfo.add
+                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
+                                      (short) 1, (short) 0,
+                                      wordSpaceIPD, false));
+                    returnList.add
+                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                    returnList.add
+                        (new KnuthPenalty(0, 0, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthInlineBox(0, 0, 0, 0,
+                                      new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, -1), true));
+                    iNextStart ++;
+                    break;
+
+                case EN_START  : // fall through
+                case EN_END    :
+                    vecAreaInfo.add
+                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
+                                      (short) 1, (short) 0,
+                                      wordSpaceIPD, false));
+                    returnList.add
+                        (new KnuthGlue(0, 3 * wordSpaceIPD.opt, 0,
+                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                    returnList.add
+                        (new KnuthPenalty(0, 0, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       - 3 * wordSpaceIPD.opt, 0,
+                                       new LeafPosition(this, -1), true));
+                    iNextStart ++;
+                    break;
+
+                case EN_JUSTIFY:
+                    vecAreaInfo.add
+                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
+                                      (short) 1, (short) 0,
+                                      wordSpaceIPD, false));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       wordSpaceIPD.max - wordSpaceIPD.opt,
+                                       wordSpaceIPD.opt - wordSpaceIPD.min,
+                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                    iNextStart ++;
+                    break;
+
+                default:
+                    vecAreaInfo.add
+                        (new AreaInfo(iNextStart, (short) (iNextStart + 1),
+                                      (short) 1, (short) 0,
+                                      wordSpaceIPD, false));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       wordSpaceIPD.max - wordSpaceIPD.opt, 0,
+                                       new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                    iNextStart ++;
+                }
+            } else if (textArray[iNextStart] == NBSPACE) {
+                // non breaking space
+                vecAreaInfo.add
+                    (new AreaInfo(iNextStart, (short) (iNextStart + 1),
+                                  (short) 1, (short) 0,
+                                  wordSpaceIPD, false));
+                returnList.add
+                    (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                      new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                returnList.add
+                    (new KnuthGlue(wordSpaceIPD.opt,
+                                   wordSpaceIPD.max - wordSpaceIPD.opt,
+                                   wordSpaceIPD.opt - wordSpaceIPD.min,
+                                   new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                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
+                    (new KnuthPenalty(0, -KnuthElement.INFINITE,
+                                      false, null, false));
+                iNextStart ++;
+                return returnList;
+            } else {
+                // the beginning of a word
+                iThisStart = iNextStart;
+                iTempStart = iNextStart;
+                MinOptMax wordIPD = new MinOptMax(0);
+                for (; iTempStart < textArray.length
+                        && textArray[iTempStart] != SPACE
+                        && textArray[iTempStart] != NBSPACE
+                     && textArray[iTempStart] != NEWLINE
+                     && !(iTempStart > iNextStart
+                          && alignment == EN_JUSTIFY
+                          && BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0);
+                        iTempStart++) {
+                    wordIPD.add(fs.getCharWidth(textArray[iTempStart]));
+                }
+                int iLetterSpaces = iTempStart - iThisStart - 1;
+                wordIPD.add(MinOptMax.multiply(letterSpaceIPD, iLetterSpaces));
+                vecAreaInfo.add
+                    (new AreaInfo(iThisStart, iTempStart, (short) 0,
+                                  (short) iLetterSpaces,
+                                  wordIPD, false));
+                if (letterSpaceIPD.min == letterSpaceIPD.max) {
+                    // constant letter space; simply return a box
+                    // whose width includes letter spaces
+                    returnList.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
+                        (new KnuthInlineBox(wordIPD.opt - iLetterSpaces * letterSpaceIPD.opt,
+                                      lead, total, middle,
+                                      new LeafPosition(this, vecAreaInfo.size() - 1), false));
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(iLetterSpaces * letterSpaceIPD.opt,
+                                       iLetterSpaces * (letterSpaceIPD.max - letterSpaceIPD.opt),
+                                       iLetterSpaces * (letterSpaceIPD.opt - letterSpaceIPD.min),
+                                       new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthInlineBox(0, lead, total, middle,
+                                            new LeafPosition(this, -1), true));
+                }
+                // if the last character is '-' or '/', it could be used as a line end;
+                // add a flagged penalty element and glue element representing a suppressible 
+                // letter space if the next character is not a space
+                if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0
+                    && iTempStart < textArray.length
+                    && textArray[iTempStart] != SPACE
+                    && textArray[iTempStart] != NBSPACE) {
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
+                                          new LeafPosition(this, -1), false));
+                    returnList.add
+                        (new KnuthGlue(letterSpaceIPD.opt,
+                                       letterSpaceIPD.max - letterSpaceIPD.opt,
+                                       letterSpaceIPD.opt - letterSpaceIPD.min,
+                                       new LeafPosition(this, -1), false));
+                    // update the information in the AreaInfo, adding one more letter space
+                    AreaInfo ai = (AreaInfo) vecAreaInfo.get(vecAreaInfo.size() - 1);
+                    ai.iLScount ++;
+                }
+                iNextStart = iTempStart;
+            }
+        } // end of while
+        setFinished(true);
+        if (returnList.size() > 0) {
+            return returnList;
+        } else {
+            return null;
+        }
+    }
+
+    public List addALetterSpaceTo(List oldList) {
+        // old list contains only a box, or the sequence: box penalty glue box;
+        // 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();
+        AreaInfo ai = (AreaInfo) vecAreaInfo.get(pos.getLeafPos());
+        ai.iLScount ++;
+        ai.ipdArea.add(letterSpaceIPD);
+        if (BREAK_CHARS.indexOf(textArray[iTempStart - 1]) >= 0) {
+            // the last character could be used as a line break
+            // append new elements to oldList
+            oldListIterator = oldList.listIterator(oldList.size());
+            oldListIterator.add(new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
+                                                 new LeafPosition(this, -1), false));
+            oldListIterator.add(new KnuthGlue(letterSpaceIPD.opt,
+                                       letterSpaceIPD.max - letterSpaceIPD.opt,
+                                       letterSpaceIPD.opt - letterSpaceIPD.min,
+                                       new LeafPosition(this, -1), false));
+        } else if (letterSpaceIPD.min == letterSpaceIPD.max) {
+            // constant letter space: replace the box
+            oldListIterator.set(new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle, pos, false));
+        } else {
+            // adjustable letter space: replace the glue
+            oldListIterator.next(); // this would return the penalty element
+            oldListIterator.next(); // this would return the glue element
+            oldListIterator.set(new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
+                                              ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
+                                              ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
+                                              new LeafPosition(this, -1), true));
+        }
+        return oldList;
+    }
+
+    public void hyphenate(Position pos, HyphContext hc) {
+        AreaInfo ai
+            = (AreaInfo) vecAreaInfo.get(((LeafPosition) pos).getLeafPos());
+        int iStartIndex = ai.iStartIndex;
+        int iStopIndex;
+        boolean bNothingChanged = true;
+
+        while (iStartIndex < ai.iBreakIndex) {
+            MinOptMax newIPD = new MinOptMax(0);
+            boolean bHyphenFollows;
+
+            if (hc.hasMoreHyphPoints()
+                && (iStopIndex = iStartIndex + hc.getNextHyphPoint())
+                <= ai.iBreakIndex) {
+                // iStopIndex is the index of the first character
+                // after a hyphenation point
+                bHyphenFollows = true;
+            } else {
+                // there are no more hyphenation points,
+                // or the next one is after ai.iBreakIndex
+                bHyphenFollows = false;
+                iStopIndex = ai.iBreakIndex;
+            }
+
+            hc.updateOffset(iStopIndex - iStartIndex);
+
+            for (int i = iStartIndex; i < iStopIndex; i++) {
+                char c = textArray[i];
+                newIPD.add(new MinOptMax(fs.getCharWidth(c)));
+            }
+            // add letter spaces
+            boolean bIsWordEnd
+                = iStopIndex == ai.iBreakIndex
+                && ai.iLScount < (ai.iBreakIndex - ai.iStartIndex);
+            newIPD.add(MinOptMax.multiply(letterSpaceIPD,
+                                          (bIsWordEnd
+                                           ? (iStopIndex - iStartIndex - 1)
+                                           : (iStopIndex - iStartIndex))));
+
+            if (!(bNothingChanged
+                  && iStopIndex == ai.iBreakIndex 
+                  && bHyphenFollows == false)) {
+                // the new AreaInfo object is not equal to the old one
+                if (changeList == null) {
+                    changeList = new LinkedList();
+                }
+                changeList.add
+                    (new PendingChange
+                     (new AreaInfo((short) iStartIndex, (short) iStopIndex,
+                                   (short) 0,
+                                   (short) (bIsWordEnd
+                                            ? (iStopIndex - iStartIndex - 1)
+                                            : (iStopIndex - iStartIndex)),
+                                   newIPD, bHyphenFollows),
+                      ((LeafPosition) pos).getLeafPos()));
+                bNothingChanged = false;
+            }
+            iStartIndex = iStopIndex;
+        }
+        if (!bChanged && !bNothingChanged) {
+            bChanged = true;
+        }
+    }
+
+    public boolean applyChanges(List oldList) {
+        setFinished(false);
+
+        if (changeList != null) {
+            int iAddedAI = 0;
+            int iRemovedAI = 0;
+            int iOldIndex = -1;
+            PendingChange currChange = null;
+            ListIterator changeListIterator = changeList.listIterator();
+            while (changeListIterator.hasNext()) {
+                currChange = (PendingChange) changeListIterator.next();
+                if (currChange.index != iOldIndex) {
+                    iRemovedAI ++;
+                    iAddedAI ++;
+                    iOldIndex = currChange.index;
+                    vecAreaInfo.remove(currChange.index + iAddedAI - iRemovedAI);
+                    vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI,
+                                    currChange.ai);
+                } else {
+                    iAddedAI ++;
+                    vecAreaInfo.add(currChange.index + iAddedAI - iRemovedAI,
+                                    currChange.ai);
+                }
+            }
+            changeList.clear();
+        }
+
+        iReturnedIndex = 0;
+        return bChanged;
+    }
+
+    public LinkedList getChangedKnuthElements(List oldList,
+                                              /*int flaggedPenalty,*/
+                                              int alignment) {
+        if (isFinished()) {
+            return null;
+        }
+
+        LinkedList returnList = new LinkedList();
+
+        while (iReturnedIndex < vecAreaInfo.size()) {
+            AreaInfo ai = (AreaInfo) vecAreaInfo.get(iReturnedIndex);
+            if (ai.iWScount == 0) {
+                // ai refers either to a word or a word fragment
+
+                // if the last character is '-' or '/' and the next character is not a space
+                // one of the letter spaces must be represented using a penalty and a glue,
+                // and its width must be subtracted
+                if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
+                    && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
+                    ai.ipdArea.add(new MinOptMax(-letterSpaceIPD.min, -letterSpaceIPD.opt, -letterSpaceIPD.max));
+                }
+                if (letterSpaceIPD.min == letterSpaceIPD.max) {
+                    returnList.add
+                        (new KnuthInlineBox(ai.ipdArea.opt, lead, total, middle,
+                                      new LeafPosition(this, iReturnedIndex), false));
+                } else {
+                    returnList.add
+                        (new KnuthInlineBox(ai.ipdArea.opt
+                                      - ai.iLScount * letterSpaceIPD.opt,
+                                      lead, total, middle, 
+                                      new LeafPosition(this, iReturnedIndex), false));
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(ai.iLScount * letterSpaceIPD.opt,
+                                       ai.iLScount * (letterSpaceIPD.max - letterSpaceIPD.opt),
+                                       ai.iLScount * (letterSpaceIPD.opt - letterSpaceIPD.min),
+                                       new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthInlineBox(0, 0, 0, 0,
+                                      new LeafPosition(this, -1), true));
+                }
+                if (ai.bHyphenated) {
+                    returnList.add
+                        (new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true,
+                                          new LeafPosition(this, -1), false));
+                }
+                // if the last character is '-' or '/', it could be used as a line end;
+                // add a flagged penalty element and a glue element representing a suppressible 
+                // letter space if the next character is not a space
+                if (BREAK_CHARS.indexOf(textArray[ai.iBreakIndex - 1]) >= 0
+                    && ai.iLScount == (ai.iBreakIndex - ai.iStartIndex)) {
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthPenalty.FLAGGED_PENALTY, true,
+                                          new LeafPosition(this, -1), false));
+                    returnList.add
+                        (new KnuthGlue(letterSpaceIPD.opt,
+                                       letterSpaceIPD.max - letterSpaceIPD.opt,
+                                       letterSpaceIPD.opt - letterSpaceIPD.min,
+                                       new LeafPosition(this, -1), false));
+                }
+                iReturnedIndex ++;
+            } else {
+                // ai refers to a space
+                if (textArray[ai.iStartIndex] == NBSPACE) {
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, -1),
+                                          false));
+                }
+                switch (alignment) {
+                case EN_CENTER :
+                    returnList.add
+                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, iReturnedIndex), false));
+                    returnList.add
+                        (new KnuthPenalty(0, 0, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       - 6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthInlineBox(0, 0, 0, 0,
+                                      new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthPenalty(0, KnuthElement.INFINITE, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, -1), true));
+                    iReturnedIndex ++;
+                    break;
+                case EN_START  : // fall through
+                case EN_END    :
+                    returnList.add
+                        (new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, iReturnedIndex), false));
+                    returnList.add
+                        (new KnuthPenalty(0, 0, false,
+                                          new LeafPosition(this, -1), true));
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       - 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                                       new LeafPosition(this, -1), true));
+                    iReturnedIndex ++;
+                    break;
+                case EN_JUSTIFY:
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       wordSpaceIPD.max - wordSpaceIPD.opt,
+                                       wordSpaceIPD.opt - wordSpaceIPD.min,
+                                       new LeafPosition(this, iReturnedIndex), false));
+                    iReturnedIndex ++;
+                    break;
+                    
+                default:
+                    returnList.add
+                        (new KnuthGlue(wordSpaceIPD.opt,
+                                       wordSpaceIPD.max - wordSpaceIPD.opt, 0,
+                                       new LeafPosition(this, iReturnedIndex), false));
+                    iReturnedIndex ++;
+                }
+            }
+        } // end of while
+        setFinished(true);
+        return returnList;
+    }
+
+    public void getWordChars(StringBuffer sbChars, Position pos) {
+        int iLeafValue = ((LeafPosition) pos).getLeafPos();
+        if (iLeafValue != -1) {
+            AreaInfo ai = (AreaInfo) vecAreaInfo.get(iLeafValue);
+            sbChars.append(new String(textArray, ai.iStartIndex,
+                                      ai.iBreakIndex - ai.iStartIndex));
+        }
+    }
+}
+
diff --git a/src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java
new file mode 100644 (file)
index 0000000..fedc04f
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+ * Copyright 2005 The Apache Software Foundation.\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/* $Id$ */\r
+\r
+package org.apache.fop.layoutmgr.inline;\r
+\r
+import org.apache.fop.area.inline.InlineArea;\r
+import org.apache.fop.fo.flow.Wrapper;\r
+import org.apache.fop.layoutmgr.LayoutContext;\r
+\r
+/**\r
+ * This is the layout manager for the fo:wrapper formatting object.\r
+ */\r
+public class WrapperLayoutManager extends LeafNodeLayoutManager {\r
+    \r
+    private Wrapper fobj;\r
+\r
+    /**\r
+     * Creates a new LM for fo:wrapper.\r
+     * @param node the fo:wrapper\r
+     */\r
+    public WrapperLayoutManager(Wrapper node) {\r
+        super(node);\r
+        fobj = node;\r
+    }\r
+\r
+    /** @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager */\r
+    public InlineArea get(LayoutContext context) {\r
+        //Create a zero-width, zero-height dummy area so this node can \r
+        //participate in the ID handling. Otherwise, addId() wouldn't \r
+        //be called.\r
+        InlineArea area = new InlineArea();\r
+        return area;\r
+    }\r
+    \r
+    /** @see org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager#addId() */\r
+    protected void addId() {\r
+        getPSLM().addIDToPage(fobj.getId());\r
+    }\r
+    \r
+}\r