]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Bugzilla #48071: made the MinOptMax class immutable. Also, lots of clean ups and...
authorVincent Hennebert <vhennebert@apache.org>
Tue, 22 Dec 2009 17:20:51 +0000 (17:20 +0000)
committerVincent Hennebert <vhennebert@apache.org>
Tue, 22 Dec 2009 17:20:51 +0000 (17:20 +0000)
Patch submitted by Alexander Kiel.

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

52 files changed:
src/java/org/apache/fop/area/Area.java
src/java/org/apache/fop/fo/properties/LengthRangeProperty.java
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
src/java/org/apache/fop/layoutmgr/Adjustment.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/BlockLevelLayoutManager.java
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/BorderOrPaddingElement.java
src/java/org/apache/fop/layoutmgr/ElementListUtils.java
src/java/org/apache/fop/layoutmgr/FootnoteBodyLayoutManager.java
src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
src/java/org/apache/fop/layoutmgr/KnuthBox.java
src/java/org/apache/fop/layoutmgr/KnuthElement.java
src/java/org/apache/fop/layoutmgr/KnuthGlue.java
src/java/org/apache/fop/layoutmgr/LayoutContext.java
src/java/org/apache/fop/layoutmgr/LeafPosition.java
src/java/org/apache/fop/layoutmgr/MinOptMaxUtil.java [deleted file]
src/java/org/apache/fop/layoutmgr/PageBreaker.java
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
src/java/org/apache/fop/layoutmgr/SpaceElement.java
src/java/org/apache/fop/layoutmgr/SpaceResolver.java
src/java/org/apache/fop/layoutmgr/SpaceSpecifier.java
src/java/org/apache/fop/layoutmgr/TraitSetter.java
src/java/org/apache/fop/layoutmgr/inline/CharacterLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/InlineLevelLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java
src/java/org/apache/fop/layoutmgr/inline/LeaderLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/LeafNodeLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/PageNumberCitationLastLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/PageNumberLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
src/java/org/apache/fop/layoutmgr/inline/WrapperLayoutManager.java
src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableStepper.java
src/java/org/apache/fop/traits/MinOptMax.java
src/java/org/apache/fop/traits/SpaceVal.java
test/java/org/apache/fop/StandardTestSuite.java
test/java/org/apache/fop/traits/MinOptMaxTest.java [new file with mode: 0644]

index 87ba2146a0f98305353c5e64a108b097dae86100..ddf2f5198053af5b75ac247cb99818d4456b2091 100644 (file)
@@ -119,7 +119,7 @@ public class Area extends AreaTreeObject implements Serializable {
     public static final int CLASS_MAX = CLASS_SIDE_FLOAT + 1;
 
     private int areaClass = CLASS_NORMAL;
-    
+
     /** the area's inline-progression-dimension */
     protected int ipd;
 
@@ -174,18 +174,18 @@ public class Area extends AreaTreeObject implements Serializable {
      * @see <a href="http://www.w3.org/TR/xsl/#inline-progression-dimension">ipd</a>
      */
     public int getIPD() {
-        return this.ipd;
+        return ipd;
     }
 
     /**
      * Set the block progression dimension of the content rectangle
      * for this area.
      *
-     * @param b the new block progression dimension
+     * @param bpd the new block progression dimension
      * @see <a href="http://www.w3.org/TR/xsl/#block-progression-dimension">bpd</a>
      */
-    public void setBPD(int b) {
-        bpd = b;
+    public void setBPD(int bpd) {
+        this.bpd = bpd;
     }
 
     /**
index 3161fc517ece95e5c801fffd0075bb7f7c0c644e..d8e8ee272b0854dc50368e31e1b97f5f556d41c7 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
+import org.apache.fop.traits.MinOptMax;
 
 /**
  * Superclass for properties that contain LengthRange values
@@ -39,6 +40,22 @@ public class LengthRangeProperty extends Property implements CompoundDatatype {
     private int bfSet = 0;    // bit field
     private boolean consistent = false;
 
+    /**
+     * Converts this <code>LengthRangeProperty</code> to a <code>MinOptMax</code>.
+     *
+     * @param context Percentage evaluation context
+     * @return the requested MinOptMax instance
+     */
+    public MinOptMax toMinOptMax(PercentBaseContext context) {
+        int min = getMinimum(context).isAuto() ? 0
+                : getMinimum(context).getLength().getValue(context);
+        int opt = getOptimum(context).isAuto() ? min
+                : getOptimum(context).getLength().getValue(context);
+        int max = getMaximum(context).isAuto() ? Integer.MAX_VALUE
+                : getMaximum(context).getLength().getValue(context);
+        return MinOptMax.getInstance(min, opt, max);
+    }
+
     /**
      * Inner class for a Maker for LengthProperty objects
      */
index a58f5523b0fa25df4cb9d117e50adf6e51e607be..db0edb42c785f50e685bb45f530b6ee651e2a0f3 100644 (file)
@@ -201,7 +201,7 @@ public abstract class AbstractBreaker {
     protected int alignment;
     private int alignmentLast;
 
-    protected MinOptMax footnoteSeparatorLength = new MinOptMax(0);
+    protected MinOptMax footnoteSeparatorLength = MinOptMax.ZERO;
 
     protected abstract int getCurrentDisplayAlign();
     protected abstract boolean hasMoreContent();
@@ -307,7 +307,7 @@ public abstract class AbstractBreaker {
      */
     public void doLayout(int flowBPD, boolean autoHeight) {
         LayoutContext childLC = createLayoutContext();
-        childLC.setStackLimitBP(new MinOptMax(flowBPD));
+        childLC.setStackLimitBP(MinOptMax.getInstance(flowBPD));
 
         if (getCurrentDisplayAlign() == Constants.EN_X_FILL) {
             //EN_X_FILL is non-standard (by LF)
@@ -613,7 +613,7 @@ public abstract class AbstractBreaker {
                     int averageLineLength = optimizeLineLength(effectiveList,
                             startElementIndex, endElementIndex);
                     if (averageLineLength != 0) {
-                        childLC.setStackLimitBP(new MinOptMax(averageLineLength));
+                        childLC.setStackLimitBP(MinOptMax.getInstance(averageLineLength));
                     }
                 }
                 /* *** *** non-standard extension *** *** */
@@ -762,7 +762,8 @@ public abstract class AbstractBreaker {
      * @param endElementIndex   index of the element ending the range
      * @return the average line length, 0 if there's no content
      */
-    private int optimizeLineLength(KnuthSequence effectiveList, int startElementIndex, int endElementIndex) {
+    private int optimizeLineLength(KnuthSequence effectiveList, int startElementIndex,
+            int endElementIndex) {
         ListIterator effectiveListIterator;
         // optimize line length
         int boxCount = 0;
@@ -783,9 +784,9 @@ public abstract class AbstractBreaker {
                     accumulatedLineLength += ((KnuthBlockBox) tempEl)
                             .getBPD();
                 }
-                if (blockBox.getIPDRange().min > greatestMinimumLength) {
+                if (blockBox.getIPDRange().getMin() > greatestMinimumLength) {
                     greatestMinimumLength = blockBox
-                            .getIPDRange().min;
+                            .getIPDRange().getMin();
                 }
             }
         }
@@ -808,7 +809,8 @@ public abstract class AbstractBreaker {
      * @param availableBPD the available BPD
      * @return the effective list
      */
-    private BlockSequence justifyBoxes(BlockSequence blockList, PageBreakingAlgorithm alg, int availableBPD) {
+    private BlockSequence justifyBoxes(BlockSequence blockList, PageBreakingAlgorithm alg,
+            int availableBPD) {
         int iOptPageNumber;
         alg.setConstantLineWidth(availableBPD);
         iOptPageNumber = alg.findBreakingPoints(blockList, /*availableBPD,*/
@@ -857,8 +859,8 @@ public abstract class AbstractBreaker {
 
             // scan the sub-sequence representing a page,
             // collecting information about potential adjustments
-            MinOptMax lineNumberMaxAdjustment = new MinOptMax(0);
-            MinOptMax spaceMaxAdjustment = new MinOptMax(0);
+            MinOptMax lineNumberMaxAdjustment = MinOptMax.ZERO;
+            MinOptMax spaceMaxAdjustment = MinOptMax.ZERO;
             double spaceAdjustmentRatio = 0.0;
             LinkedList blockSpacesList = new LinkedList();
             LinkedList unconfirmedList = new LinkedList();
@@ -872,30 +874,23 @@ public abstract class AbstractBreaker {
                     // glue elements are used to represent adjustable
                     // lines
                     // and adjustable spaces between blocks
-                    switch (((KnuthGlue) thisElement)
-                            .getAdjustmentClass()) {
-                    case BlockLevelLayoutManager.SPACE_BEFORE_ADJUSTMENT:
-                    // fall through
-                    case BlockLevelLayoutManager.SPACE_AFTER_ADJUSTMENT:
+                    Adjustment adjustment = ((KnuthGlue) thisElement).getAdjustmentClass();
+                    if (adjustment.equals(Adjustment.SPACE_BEFORE_ADJUSTMENT)
+                            || adjustment.equals(Adjustment.SPACE_AFTER_ADJUSTMENT)) {
                         // potential space adjustment
                         // glue items before the first box or after the
                         // last one
                         // must be ignored
                         unconfirmedList.add(thisElement);
-                        break;
-                    case BlockLevelLayoutManager.LINE_NUMBER_ADJUSTMENT:
+                    } else if (adjustment.equals(Adjustment.LINE_NUMBER_ADJUSTMENT)) {
                         // potential line number adjustment
-                        lineNumberMaxAdjustment.max += ((KnuthGlue) thisElement)
-                                .getStretch();
-                        lineNumberMaxAdjustment.min -= ((KnuthGlue) thisElement)
-                                .getShrink();
+                        lineNumberMaxAdjustment
+                                = lineNumberMaxAdjustment.plusMax(thisElement.getStretch());
+                        lineNumberMaxAdjustment
+                                = lineNumberMaxAdjustment.minusMin(thisElement.getShrink());
                         adjustableLinesList.add(thisElement);
-                        break;
-                    case BlockLevelLayoutManager.LINE_HEIGHT_ADJUSTMENT:
+                    } else if (adjustment.equals(Adjustment.LINE_HEIGHT_ADJUSTMENT)) {
                         // potential line height adjustment
-                        break;
-                    default:
-                    // nothing
                     }
                 } else if (thisElement.isBox()) {
                     if (!bBoxSeen) {
@@ -909,10 +904,8 @@ public abstract class AbstractBreaker {
                             // blockSpaceList
                             KnuthGlue blockSpace = (KnuthGlue) unconfirmedList
                                     .removeFirst();
-                            spaceMaxAdjustment.max += ((KnuthGlue) blockSpace)
-                                    .getStretch();
-                            spaceMaxAdjustment.min -= ((KnuthGlue) blockSpace)
-                                    .getShrink();
+                            spaceMaxAdjustment = spaceMaxAdjustment.plusMax(blockSpace.getStretch());
+                            spaceMaxAdjustment = spaceMaxAdjustment.minusMin(blockSpace.getShrink());
                             blockSpacesList.add(blockSpace);
                         }
                     }
@@ -931,16 +924,19 @@ public abstract class AbstractBreaker {
             }
 
             if (thisBreak.bpdAdjust != 0
-                    && (thisBreak.difference > 0 && thisBreak.difference <= spaceMaxAdjustment.max)
-                    || (thisBreak.difference < 0 && thisBreak.difference >= spaceMaxAdjustment.min)) {
+                    && (thisBreak.difference > 0 && thisBreak.difference <= spaceMaxAdjustment
+                            .getMax())
+                    || (thisBreak.difference < 0 && thisBreak.difference >= spaceMaxAdjustment
+                            .getMin())) {
                 // modify only the spaces between blocks
-                spaceAdjustmentRatio = ((double) thisBreak.difference / (thisBreak.difference > 0 ? spaceMaxAdjustment.max
-                        : spaceMaxAdjustment.min));
+                spaceAdjustmentRatio = ((double) thisBreak.difference / (thisBreak.difference > 0
+                        ? spaceMaxAdjustment.getMax()
+                        : spaceMaxAdjustment.getMin()));
                 adjustedDiff += adjustBlockSpaces(
                         blockSpacesList,
                         thisBreak.difference,
-                        (thisBreak.difference > 0 ? spaceMaxAdjustment.max
-                                : -spaceMaxAdjustment.min));
+                        (thisBreak.difference > 0 ? spaceMaxAdjustment.getMax()
+                                : -spaceMaxAdjustment.getMin()));
                 log.debug("single space: "
                         + (adjustedDiff == thisBreak.difference
                                 || thisBreak.bpdAdjust == 0 ? "ok"
@@ -949,13 +945,13 @@ public abstract class AbstractBreaker {
                 adjustedDiff += adjustLineNumbers(
                         adjustableLinesList,
                         thisBreak.difference,
-                        (thisBreak.difference > 0 ? lineNumberMaxAdjustment.max
-                                : -lineNumberMaxAdjustment.min));
+                        (thisBreak.difference > 0 ? lineNumberMaxAdjustment.getMax()
+                                : -lineNumberMaxAdjustment.getMin()));
                 adjustedDiff += adjustBlockSpaces(
                         blockSpacesList,
                         thisBreak.difference - adjustedDiff,
-                        ((thisBreak.difference - adjustedDiff) > 0 ? spaceMaxAdjustment.max
-                                : -spaceMaxAdjustment.min));
+                        ((thisBreak.difference - adjustedDiff) > 0 ? spaceMaxAdjustment.getMax()
+                                : -spaceMaxAdjustment.getMin()));
                 log.debug("lines and space: "
                         + (adjustedDiff == thisBreak.difference
                                 || thisBreak.bpdAdjust == 0 ? "ok"
index e6a5bea5eff03ff1950b2042382086c343c34794..1f91cef1a1bc6a7f2725e048a6eb7b7343576d2d 100644 (file)
@@ -48,7 +48,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
     private static Log log = LogFactory.getLog(AbstractLayoutManager.class);
 
     /** Parent LayoutManager for this LayoutManager */
-    protected LayoutManager parentLM;
+    protected LayoutManager parentLayoutManager;
     /** List of child LayoutManagers */
     protected List childLMs;
     /** Iterator for child LayoutManagers */
@@ -91,12 +91,12 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
 
     /** {@inheritDoc} */
     public void setParent(LayoutManager lm) {
-        this.parentLM = lm;
+        this.parentLayoutManager = lm;
     }
 
     /** {@inheritDoc} */
     public LayoutManager getParent() {
-        return this.parentLM;
+        return this.parentLayoutManager;
     }
 
     /** {@inheritDoc} */
@@ -230,7 +230,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
 
     /** {@inheritDoc} */
     public PageSequenceLayoutManager getPSLM() {
-        return parentLM.getPSLM();
+        return parentLayoutManager.getPSLM();
     }
 
     /**
@@ -442,7 +442,7 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
              * LM is a descendant of the FlowLM. For static-content
              * the FO may still be needed on following pages.
              */
-            LayoutManager lm = this.parentLM;
+            LayoutManager lm = this.parentLayoutManager;
             while (!(lm instanceof FlowLayoutManager
                         || lm instanceof PageSequenceLayoutManager)) {
                 lm = lm.getParent();
diff --git a/src/java/org/apache/fop/layoutmgr/Adjustment.java b/src/java/org/apache/fop/layoutmgr/Adjustment.java
new file mode 100644 (file)
index 0000000..0a96fb2
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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;
+
+/**
+ * @see KnuthGlue
+ * @see "http://www.leverkruid.eu/GKPLinebreaking/elements.html"
+ */
+public final class Adjustment {
+
+    /**
+     * Adjustment class: no adjustment.
+     */
+    public static final Adjustment NO_ADJUSTMENT = new Adjustment("none");
+
+    /**
+     * Adjustment class: adjustment for space-before.
+     */
+    public static final Adjustment SPACE_BEFORE_ADJUSTMENT = new Adjustment("space-before");
+
+    /**
+     * Adjustment class: adjustment for space-after.
+     */
+    public static final Adjustment SPACE_AFTER_ADJUSTMENT = new Adjustment("space-after");
+
+    /**
+     * Adjustment class: adjustment for number of lines.
+     */
+    public static final Adjustment LINE_NUMBER_ADJUSTMENT = new Adjustment("line-number");
+
+    /**
+     * Adjustment class: adjustment for line height.
+     */
+    public static final Adjustment LINE_HEIGHT_ADJUSTMENT = new Adjustment("line-height");
+
+    private final String name;
+
+    private Adjustment(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object obj) {
+        return this == obj;
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return name;
+    }
+}
index 3378d86d7aec6b8287014a6fd594c6319644181e..5ca2b567f20bba29f448cdd9aa3643affe275120 100644 (file)
@@ -107,8 +107,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
         startIndent = getBlockContainerFO().getCommonMarginBlock().startIndent.getValue(this);
         endIndent = getBlockContainerFO().getCommonMarginBlock().endIndent.getValue(this);
 
-        boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
-        if (rotated) {
+        if (blockProgressionDirectionChanges()) {
             height = getBlockContainerFO().getInlineProgressionDimension()
                             .getOptimum(this).getLength();
             width = getBlockContainerFO().getBlockProgressionDimension()
@@ -156,10 +155,6 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
         return (overflow == EN_HIDDEN || overflow == EN_ERROR_IF_OVERFLOW);
     }
 
-    private int getSpaceBefore() {
-        return foBlockSpaceBefore.opt;
-    }
-
     private int getBPIndents() {
         int indents = 0;
         /* TODO This is wrong isn't it?
@@ -200,7 +195,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
 
         autoHeight = false;
         //boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
-        int maxbpd = context.getStackLimitBP().opt;
+        int maxbpd = context.getStackLimitBP().getOpt();
         int allocBPD;
         if (height.getEnum() == EN_AUTO
                 || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
@@ -246,7 +241,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                     getBlockContainerFO().getLocator());
         }
 
-        MinOptMax stackLimit = new MinOptMax(relDims.bpd);
+        MinOptMax stackLimit = MinOptMax.getInstance(relDims.bpd);
 
         List returnedList;
         List contentList = new LinkedList();
@@ -279,7 +274,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                 LayoutContext childLC = new LayoutContext(0);
                 childLC.copyPendingMarksFrom(context);
                 // curLM is a ?
-                childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+                childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
                 childLC.setRefIPD(relDims.ipd);
                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
                 if (curLM == this.childLMs.get(0)) {
@@ -349,41 +344,8 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
             wrapPositionElements(contentList, returnList);
 
         } else {
-            MinOptMax range = new MinOptMax(relDims.ipd);
-            BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
-            breaker.doLayout(relDims.bpd, autoHeight);
-            boolean contentOverflows = breaker.isOverflow();
-            if (autoHeight) {
-                //Update content BPD now that it is known
-                int newHeight = breaker.deferredAlg.totalWidth;
-                boolean switchedProgressionDirection
-                    = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
-                if (switchedProgressionDirection) {
-                    setContentAreaIPD(newHeight);
-                } else {
-                    vpContentBPD = newHeight;
-                }
-                updateRelDims(contentRectOffsetX, contentRectOffsetY, false);
-            }
-
-            Position bcPosition = new BlockContainerPosition(this, breaker);
-            returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false));
-            //TODO Handle min/opt/max for block-progression-dimension
-            /* These two elements will be used to add stretchability to the above box
-            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
-                                   false, returnPosition, false));
-            returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
-                                   LINE_NUMBER_ADJUSTMENT, returnPosition, false));
-            */
-
-            if (contentOverflows) {
-                BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
-                        getBlockContainerFO().getUserAgent().getEventBroadcaster());
-                boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
-                eventProducer.viewportOverflow(this, getBlockContainerFO().getName(),
-                        breaker.getOverflowAmount(), needClip(), canRecover,
-                        getBlockContainerFO().getLocator());
-            }
+            returnList.add(refactoredBecauseOfDuplicateCode(contentRectOffsetX,
+                    contentRectOffsetY));
         }
         addKnuthElementsForBorderPaddingAfter(returnList, true);
         addKnuthElementsForSpaceAfter(returnList, alignment);
@@ -398,6 +360,49 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
         return returnList;
     }
 
+    private KnuthBox refactoredBecauseOfDuplicateCode(double contentRectOffsetX,
+                                                      double contentRectOffsetY) {
+
+        MinOptMax range = MinOptMax.getInstance(relDims.ipd);
+        BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
+        breaker.doLayout(relDims.bpd, autoHeight);
+        boolean contentOverflows = breaker.isOverflow();
+        if (autoHeight) {
+            //Update content BPD now that it is known
+            int newHeight = breaker.deferredAlg.totalWidth;
+            if (blockProgressionDirectionChanges()) {
+                setContentAreaIPD(newHeight);
+            } else {
+                vpContentBPD = newHeight;
+            }
+            updateRelDims(contentRectOffsetX, contentRectOffsetY, false);
+        }
+
+        Position bcPosition = new BlockContainerPosition(this, breaker);
+        KnuthBox knuthBox = new KnuthBox(vpContentBPD, notifyPos(bcPosition), false);
+        //TODO Handle min/opt/max for block-progression-dimension
+        /* These two elements will be used to add stretchability to the above box
+    returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
+                           false, returnPosition, false));
+    returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+                           LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+    */
+
+        if (contentOverflows) {
+            BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
+                    getBlockContainerFO().getUserAgent().getEventBroadcaster());
+            boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
+            eventProducer.viewportOverflow(this, getBlockContainerFO().getName(),
+                    breaker.getOverflowAmount(), needClip(), canRecover,
+                    getBlockContainerFO().getLocator());
+        }
+        return knuthBox;
+    }
+
+    private boolean blockProgressionDirectionChanges() {
+        return getBlockContainerFO().getReferenceOrientation() % 180 != 0;
+    }
+
     /** {@inheritDoc} */
     public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
             Position restartPosition, LayoutManager restartAtLM) {
@@ -408,7 +413,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
 
         autoHeight = false;
         //boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
-        int maxbpd = context.getStackLimitBP().opt;
+        int maxbpd = context.getStackLimitBP().getOpt();
         int allocBPD;
         if (height.getEnum() == EN_AUTO
                 || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
@@ -454,7 +459,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                     getBlockContainerFO().getLocator());
         }
 
-        MinOptMax stackLimit = new MinOptMax(relDims.bpd);
+        MinOptMax stackLimit = MinOptMax.getInstance(relDims.bpd);
 
         List returnedList;
         List contentList = new LinkedList();
@@ -492,7 +497,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                 setCurrentChildLM(curLM);
 
                 childLC.copyPendingMarksFrom(context);
-                childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+                childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
                 childLC.setRefIPD(relDims.ipd);
                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
                 if (curLM == this.childLMs.get(0)) {
@@ -507,7 +512,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                 setCurrentChildLM(curLM);
 
                 childLC.copyPendingMarksFrom(context);
-                childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+                childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
                 childLC.setRefIPD(relDims.ipd);
                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
                 if (curLM == this.childLMs.get(0)) {
@@ -578,7 +583,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                 childLC = new LayoutContext(0);
                 childLC.copyPendingMarksFrom(context);
                 // curLM is a ?
-                childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+                childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
                 childLC.setRefIPD(relDims.ipd);
                 childLC.setWritingMode(getBlockContainerFO().getWritingMode());
                 if (curLM == this.childLMs.get(0)) {
@@ -649,41 +654,8 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
             wrapPositionElements(contentList, returnList);
 
         } else {
-            MinOptMax range = new MinOptMax(relDims.ipd);
-            BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
-            breaker.doLayout(relDims.bpd, autoHeight);
-            boolean contentOverflows = breaker.isOverflow();
-            if (autoHeight) {
-                //Update content BPD now that it is known
-                int newHeight = breaker.deferredAlg.totalWidth;
-                boolean switchedProgressionDirection
-                    = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
-                if (switchedProgressionDirection) {
-                    setContentAreaIPD(newHeight);
-                } else {
-                    vpContentBPD = newHeight;
-                }
-                updateRelDims(contentRectOffsetX, contentRectOffsetY, false);
-            }
-
-            Position bcPosition = new BlockContainerPosition(this, breaker);
-            returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false));
-            //TODO Handle min/opt/max for block-progression-dimension
-            /* These two elements will be used to add stretchability to the above box
-            returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
-                                   false, returnPosition, false));
-            returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
-                                   LINE_NUMBER_ADJUSTMENT, returnPosition, false));
-            */
-
-            if (contentOverflows) {
-                BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
-                        getBlockContainerFO().getUserAgent().getEventBroadcaster());
-                boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
-                eventProducer.viewportOverflow(this, getBlockContainerFO().getName(),
-                        breaker.getOverflowAmount(), needClip(), canRecover,
-                        getBlockContainerFO().getLocator());
-            }
+            returnList.add(refactoredBecauseOfDuplicateCode(contentRectOffsetX,
+                    contentRectOffsetY));
         }
         addKnuthElementsForBorderPaddingAfter(returnList, true);
         addKnuthElementsForSpaceAfter(returnList, alignment);
@@ -706,8 +678,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
     private List getNextKnuthElementsAbsolute(LayoutContext context, int alignment) {
         autoHeight = false;
 
-        boolean switchedProgressionDirection
-            = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
+        boolean bpDirectionChanges = blockProgressionDirectionChanges();
         Point offset = getAbsOffset();
         int allocBPD, allocIPD;
         if (height.getEnum() == EN_AUTO
@@ -720,7 +691,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                 if (isFixed()) {
                     availHeight = (int)getCurrentPV().getViewArea().getHeight();
                 } else {
-                    availHeight = context.getStackLimitBP().opt;
+                    availHeight = context.getStackLimitBP().getOpt();
                 }
                 allocBPD = availHeight;
                 allocBPD -= offset.y;
@@ -753,8 +724,8 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                     }
                 }
             } else {
-                allocBPD = context.getStackLimitBP().opt;
-                if (!switchedProgressionDirection) {
+                allocBPD = context.getStackLimitBP().getOpt();
+                if (!bpDirectionChanges) {
                     autoHeight = true;
                 }
             }
@@ -798,7 +769,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                     */
                     allocIPD = 0;
                 }
-                if (switchedProgressionDirection) {
+                if (bpDirectionChanges) {
                     autoHeight = true;
                 }
             }
@@ -812,14 +783,14 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
 
         updateRelDims(0, 0, autoHeight);
 
-        MinOptMax range = new MinOptMax(relDims.ipd);
+        MinOptMax range = MinOptMax.getInstance(relDims.ipd);
         BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
         breaker.doLayout((autoHeight ? 0 : relDims.bpd), autoHeight);
         boolean contentOverflows = breaker.isOverflow();
         if (autoHeight) {
             //Update content BPD now that it is known
             int newHeight = breaker.deferredAlg.totalWidth;
-            if (switchedProgressionDirection) {
+            if (bpDirectionChanges) {
                 setContentAreaIPD(newHeight);
             } else {
                 vpContentBPD = newHeight;
@@ -928,7 +899,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
 
         protected LayoutContext createLayoutContext() {
             LayoutContext lc = super.createLayoutContext();
-            lc.setRefIPD(ipd.opt);
+            lc.setRefIPD(ipd.getOpt());
             lc.setWritingMode(getBlockContainerFO().getWritingMode());
             return lc;
         }
@@ -1026,7 +997,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
         // if this will create the first block area in a page
         // and display-align is bottom or center, add space before
         if (layoutContext.getSpaceBefore() > 0) {
-            addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+            addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
         }
 
         LayoutManager childLM;
@@ -1150,20 +1121,20 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
                     foBlockSpaceAfter = new SpaceVal(getBlockContainerFO()
                                 .getCommonMarginBlock().spaceAfter, this).getSpace();
                     adjustedSpaceBefore = (neededUnits(splitLength
-                            + foBlockSpaceBefore.min
-                            + foBlockSpaceAfter.min)
+                            + foBlockSpaceBefore.getMin()
+                            + foBlockSpaceAfter.getMin())
                             * bpUnit - splitLength) / 2;
                     adjustedSpaceAfter = neededUnits(splitLength
-                            + foBlockSpaceBefore.min
-                            + foBlockSpaceAfter.min)
+                            + foBlockSpaceBefore.getMin()
+                            + foBlockSpaceAfter.getMin())
                             * bpUnit - splitLength - adjustedSpaceBefore;
                 } else if (bSpaceBefore) {
                     adjustedSpaceBefore = neededUnits(splitLength
-                            + foBlockSpaceBefore.min)
+                            + foBlockSpaceBefore.getMin())
                             * bpUnit - splitLength;
                 } else {
                     adjustedSpaceAfter = neededUnits(splitLength
-                            + foBlockSpaceAfter.min)
+                            + foBlockSpaceAfter.getMin())
                             * bpUnit - splitLength;
                 }
                 //log.debug("space before = " + adjustedSpaceBefore
@@ -1209,8 +1180,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
      */
     public Area getParentArea(Area childArea) {
         if (referenceArea == null) {
-            boolean switchedProgressionDirection
-                = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
+            boolean switchedProgressionDirection = blockProgressionDirectionChanges();
             boolean allowBPDUpdate = autoHeight && !switchedProgressionDirection;
 
             viewportBlockArea = new BlockViewport(allowBPDUpdate);
@@ -1270,7 +1240,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
 
             // Set up dimensions
             // Must get dimensions from parent area
-            /*Area parentArea =*/ parentLM.getParentArea(referenceArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(referenceArea);
             //int referenceIPD = parentArea.getIPD();
             referenceArea.setIPD(relDims.ipd);
             // Get reference IPD from parentArea
index d7453a399513fae631e18f01a7dd309f70e67b2c..69e07a4046819814a829e7c6803a8ca76f434fdb 100644 (file)
@@ -241,7 +241,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
         // if this will create the first block area in a page
         // and display-align is after or center, add space before
         if (layoutContext.getSpaceBefore() > 0) {
-            addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+            addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
         }
 
         LayoutManager childLM;
@@ -356,20 +356,20 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
                 foSpaceAfter = new SpaceVal(getBlockFO()
                                     .getCommonMarginBlock().spaceAfter, this).getSpace();
                 adjustedSpaceBefore = (neededUnits(splitLength
-                        + foSpaceBefore.min
-                        + foSpaceAfter.min)
+                        + foSpaceBefore.getMin()
+                        + foSpaceAfter.getMin())
                         * bpUnit - splitLength) / 2;
                 adjustedSpaceAfter = neededUnits(splitLength
-                        + foSpaceBefore.min
-                        + foSpaceAfter.min)
+                        + foSpaceBefore.getMin()
+                        + foSpaceAfter.getMin())
                         * bpUnit - splitLength - adjustedSpaceBefore;
                 } else if (spaceBefore) {
                 adjustedSpaceBefore = neededUnits(splitLength
-                        + foSpaceBefore.min)
+                        + foSpaceBefore.getMin())
                         * bpUnit - splitLength;
                 } else {
                 adjustedSpaceAfter = neededUnits(splitLength
-                        + foSpaceAfter.min)
+                        + foSpaceAfter.getMin())
                         * bpUnit - splitLength;
                 }
             //log.debug("spazio prima = " + adjustedSpaceBefore
@@ -426,7 +426,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
 
             // Must get dimensions from parent area
             //Don't optimize this line away. It can have ugly side-effects.
-            /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
 
             // set traits
             TraitSetter.setProducerID(curBlockArea, getBlockFO().getId());
index 3d30abde08a57e724a96c86bef399b5843e5a23a..a1d43dd6f8668920b7150449d9959a87a9bf7290 100644 (file)
@@ -26,17 +26,6 @@ import org.apache.fop.fo.properties.KeepProperty;
  */
 public interface BlockLevelLayoutManager extends LayoutManager {
 
-    /** Adjustment class: no adjustment */
-    int NO_ADJUSTMENT = -1;
-    /** Adjustment class: adjustment for space-before */
-    int SPACE_BEFORE_ADJUSTMENT = 0;
-    /** Adjustment class: adjustment for space-after */
-    int SPACE_AFTER_ADJUSTMENT = 1;
-    /** Adjustment class: adjustment for number of lines */
-    int LINE_NUMBER_ADJUSTMENT = 2;
-    /** Adjustment class: adjustment for line height */
-    int LINE_HEIGHT_ADJUSTMENT = 3;
-
     int negotiateBPDAdjustment(int adj, KnuthElement lastElement);
 
     void discardSpace(KnuthGlue spaceGlue);
index 92a4230982fc9e593cb0ab12f68baa63127443b1..4636cb15addaee298f36ae4355cb3adee9ed582e 100644 (file)
@@ -128,7 +128,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
         if (sp != 0) {
             Block spacer = new Block();
             spacer.setBPD(sp);
-            parentLM.addChildArea(spacer);
+            parentLayoutManager.addChildArea(spacer);
         }
     }
 
@@ -177,7 +177,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
      */
     protected void flush() {
         if (getCurrentArea() != null) {
-            parentLM.addChildArea(getCurrentArea());
+            parentLayoutManager.addChildArea(getCurrentArea());
         }
     }
 
@@ -654,7 +654,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
 
         if (innerPosition == null && lastElement.isGlue()) {
             // this adjustment applies to space-before or space-after of this block
-            if (((KnuthGlue) lastElement).getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
+            if (((KnuthGlue) lastElement).getAdjustmentClass()
+                    == Adjustment.SPACE_BEFORE_ADJUSTMENT) {
                 // this adjustment applies to space-before
                 adjustedSpaceBefore += adj;
 /*LF*/          //log.debug("  BLM.negotiateBPDAdjustment> spazio prima: " + adj);
@@ -735,14 +736,14 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             // if this block has block-progression-unit > 0, innerPosition can be
             // a MappingPosition
             // spaceGlue represents space before or space after of this block
-            if (spaceGlue.getAdjustmentClass() == SPACE_BEFORE_ADJUSTMENT) {
+            if (spaceGlue.getAdjustmentClass() == Adjustment.SPACE_BEFORE_ADJUSTMENT) {
                 // space-before must be discarded
                 adjustedSpaceBefore = 0;
-                foSpaceBefore = new MinOptMax(0);
+                foSpaceBefore = MinOptMax.ZERO;
             } else {
                 // space-after must be discarded
                 adjustedSpaceAfter = 0;
-                foSpaceAfter = new MinOptMax(0);
+                foSpaceAfter = MinOptMax.ZERO;
                 //TODO Why are both cases handled in the same way?
             }
         } else {
@@ -909,10 +910,10 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             }
             if (bpUnit > 0) {
                 returnList.add(new KnuthGlue(0, 0, 0,
-                    SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
+                    Adjustment.SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
             } else {
                 returnList.add(new KnuthGlue(adjustedSpaceBefore, 0, 0,
-                    SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
+                    Adjustment.SPACE_BEFORE_ADJUSTMENT, new NonLeafPosition(this, null), true));
             }
         }
 
@@ -949,12 +950,12 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             }
             if (bpUnit > 0) {
                 returnList.add(new KnuthGlue(0, 0, 0,
-                        SPACE_AFTER_ADJUSTMENT,
+                        Adjustment.SPACE_AFTER_ADJUSTMENT,
                         new NonLeafPosition(this, null),
                         spaceAfterIsConditional));
             } else {
                 returnList.add(new KnuthGlue(adjustedSpaceAfter, 0, 0,
-                        SPACE_AFTER_ADJUSTMENT,
+                        Adjustment.SPACE_AFTER_ADJUSTMENT,
                         new NonLeafPosition(this, null),
                         spaceAfterIsConditional));
             }
@@ -1396,8 +1397,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             bAddedBoxAfter = true;
         }
 
-        MinOptMax totalLength = new MinOptMax(0);
-        MinOptMax totalUnits = new MinOptMax(0);
+        MinOptMax totalLength = MinOptMax.ZERO;
         LinkedList newList = new LinkedList();
 
         //log.debug(" Prima scansione");
@@ -1406,11 +1406,11 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
         while (oldListIterator.hasNext()) {
             KnuthElement element = (KnuthElement) oldListIterator.next();
             if (element.isBox()) {
-                totalLength.add(new MinOptMax(element.getWidth()));
+                totalLength = totalLength.plus(element.getWidth());
                 //log.debug("box " + element.getWidth());
             } else if (element.isGlue()) {
-                totalLength.min -= element.getShrink();
-                totalLength.max += element.getStretch();
+                totalLength = totalLength.minusMin(element.getShrink());
+                totalLength = totalLength.plusMax(element.getStretch());
                 //leafValue = ((LeafPosition) element.getPosition()).getLeafPos();
                 //log.debug("glue " + element.getWidth() + " + "
                 //    + ((KnuthGlue) element).getStretch() + " - "
@@ -1421,9 +1421,9 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             }
         }
         // compute the total amount of "units"
-        totalUnits = new MinOptMax(neededUnits(totalLength.min),
-                                   neededUnits(totalLength.opt),
-                                   neededUnits(totalLength.max));
+        MinOptMax totalUnits = MinOptMax.getInstance(neededUnits(totalLength.getMin()),
+                                   neededUnits(totalLength.getOpt()),
+                                   neededUnits(totalLength.getMax()));
         //log.debug(" totalLength= " + totalLength);
         //log.debug(" unita'= " + totalUnits);
 
@@ -1432,35 +1432,35 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
         // in order to compute partial min, opt and max length
         // and create the new elements
         oldListIterator = oldList.listIterator();
-        boolean bPrevIsBox = false;
-        MinOptMax lengthBeforeBreak = new MinOptMax(0);
-        MinOptMax lengthAfterBreak = (MinOptMax) totalLength.clone();
+        boolean prevIsBox;
+        MinOptMax lengthBeforeBreak = MinOptMax.ZERO;
+        MinOptMax lengthAfterBreak = totalLength;
         MinOptMax unitsBeforeBreak;
         MinOptMax unitsAfterBreak;
-        MinOptMax unsuppressibleUnits = new MinOptMax(0);
+        MinOptMax unsuppressibleUnits = MinOptMax.ZERO;
         int firstIndex = 0;
         int lastIndex = -1;
         while (oldListIterator.hasNext()) {
             KnuthElement element = (KnuthElement) oldListIterator.next();
             lastIndex++;
             if (element.isBox()) {
-                lengthBeforeBreak.add(new MinOptMax(element.getWidth()));
-                lengthAfterBreak.subtract(new MinOptMax(element.getWidth()));
-                bPrevIsBox = true;
+                lengthBeforeBreak = lengthBeforeBreak.plus(element.getWidth());
+                lengthAfterBreak = lengthAfterBreak.minus(element.getWidth());
+                prevIsBox = true;
             } else if (element.isGlue()) {
-                lengthBeforeBreak.min -= element.getShrink();
-                lengthAfterBreak.min += element.getShrink();
-                lengthBeforeBreak.max += element.getStretch();
-                lengthAfterBreak.max -= element.getStretch();
-                bPrevIsBox = false;
+                lengthBeforeBreak = lengthBeforeBreak.minusMin(element.getShrink());
+                lengthAfterBreak = lengthAfterBreak.plusMin(element.getShrink());
+                lengthBeforeBreak = lengthBeforeBreak.plusMax(element.getStretch());
+                lengthAfterBreak = lengthAfterBreak.minusMax(element.getStretch());
+                prevIsBox = false;
             } else {
-                lengthBeforeBreak.add(new MinOptMax(element.getWidth()));
-                bPrevIsBox = false;
+                lengthBeforeBreak = lengthBeforeBreak.plus(element.getWidth());
+                prevIsBox = false;
             }
 
             // create the new elements
             if (element.isPenalty() && element.getPenalty() < KnuthElement.INFINITE
-                    || element.isGlue() && bPrevIsBox
+                    || element.isGlue() && prevIsBox
                     || !oldListIterator.hasNext()) {
                 // suppress elements after the breaking point
                 int iStepsForward = 0;
@@ -1469,8 +1469,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                     iStepsForward++;
                     if (el.isGlue()) {
                         // suppressed glue
-                        lengthAfterBreak.min += el.getShrink();
-                        lengthAfterBreak.max -= el.getStretch();
+                        lengthAfterBreak = lengthAfterBreak.plusMin(el.getShrink());
+                        lengthAfterBreak = lengthAfterBreak.minusMax(el.getStretch());
                     } else if (el.isPenalty()) {
                         // suppressed penalty, do nothing
                     } else {
@@ -1479,36 +1479,37 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                     }
                 }
                 // compute the partial amount of "units" before and after the break
-                unitsBeforeBreak = new MinOptMax(neededUnits(lengthBeforeBreak.min),
-                                                 neededUnits(lengthBeforeBreak.opt),
-                                                 neededUnits(lengthBeforeBreak.max));
-                unitsAfterBreak = new MinOptMax(neededUnits(lengthAfterBreak.min),
-                                                neededUnits(lengthAfterBreak.opt),
-                                                neededUnits(lengthAfterBreak.max));
+                unitsBeforeBreak = MinOptMax.getInstance(neededUnits(lengthBeforeBreak.getMin()),
+                                                 neededUnits(lengthBeforeBreak.getOpt()),
+                                                 neededUnits(lengthBeforeBreak.getMax()));
+                unitsAfterBreak = MinOptMax.getInstance(neededUnits(lengthAfterBreak.getMin()),
+                                                neededUnits(lengthAfterBreak.getOpt()),
+                                                neededUnits(lengthAfterBreak.getMax()));
 
                 // rewind the iterator and lengthAfterBreak
                 for (int i = 0; i < iStepsForward; i++) {
                     KnuthElement el = (KnuthElement) oldListIterator.previous();
                     if (el.isGlue()) {
-                        lengthAfterBreak.min -= el.getShrink();
-                        lengthAfterBreak.max += el.getStretch();
+                        lengthAfterBreak = lengthAfterBreak.minusMin(el.getShrink());
+                        lengthAfterBreak = lengthAfterBreak.plusMax(el.getStretch());
                     }
                 }
 
                 // compute changes in length, stretch and shrink
-                int uLengthChange = unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt;
-                int uStretchChange = (unitsBeforeBreak.max + unitsAfterBreak.max - totalUnits.max)
-                    - (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt);
-                int uShrinkChange = (unitsBeforeBreak.opt + unitsAfterBreak.opt - totalUnits.opt)
-                    - (unitsBeforeBreak.min + unitsAfterBreak.min - totalUnits.min);
+                int uLengthChange = unitsBeforeBreak.getOpt() + unitsAfterBreak.getOpt()
+                        - totalUnits.getOpt();
+                int uStretchChange = unitsBeforeBreak.getStretch()
+                        + unitsAfterBreak.getStretch() - totalUnits.getStretch();
+                int uShrinkChange = unitsBeforeBreak.getShrink()
+                        + unitsAfterBreak.getShrink() - totalUnits.getShrink();
 
                 // compute the number of normal, stretch and shrink unit
                 // that must be added to the new sequence
-                int uNewNormal = unitsBeforeBreak.opt - unsuppressibleUnits.opt;
-                int uNewStretch = (unitsBeforeBreak.max - unitsBeforeBreak.opt)
-                                  - (unsuppressibleUnits.max - unsuppressibleUnits.opt);
-                int uNewShrink = (unitsBeforeBreak.opt - unitsBeforeBreak.min)
-                                 - (unsuppressibleUnits.opt - unsuppressibleUnits.min);
+                int uNewNormal = unitsBeforeBreak.getOpt() - unsuppressibleUnits.getOpt();
+                int uNewStretch = unitsBeforeBreak.getStretch()
+                        - unsuppressibleUnits.getStretch();
+                int uNewShrink = unitsBeforeBreak.getShrink()
+                        - unsuppressibleUnits.getShrink();
 
                 //log.debug("("
                 //    + unsuppressibleUnits.min + "-" + unsuppressibleUnits.opt + "-"
@@ -1539,10 +1540,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                                                                  lastIndex - lastIndexCorrection);
 
                 // new box
-                newList.add(new KnuthBox((uNewNormal - uLengthChange) * bpUnit,
-                                         mappingPos,
-                                         false));
-                unsuppressibleUnits.add(new MinOptMax(uNewNormal - uLengthChange));
+                newList.add(new KnuthBox((uNewNormal - uLengthChange) * bpUnit, mappingPos, false));
+                unsuppressibleUnits = unsuppressibleUnits.plus(uNewNormal - uLengthChange);
                 //log.debug("        box " + (uNewNormal - uLengthChange));
 
                 // new infinite penalty, glue and box, if necessary
@@ -1558,17 +1557,15 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                     newList.add(new KnuthGlue(0,
                                               iStretchUnits * bpUnit,
                                               iShrinkUnits * bpUnit,
-                                              LINE_NUMBER_ADJUSTMENT,
+                                              Adjustment.LINE_NUMBER_ADJUSTMENT,
                                               mappingPos,
                                               false));
                     //log.debug("        PENALTY");
                     //log.debug("        glue 0 " + iStretchUnits + " " + iShrinkUnits);
-                    unsuppressibleUnits.max += iStretchUnits;
-                    unsuppressibleUnits.min -= iShrinkUnits;
+                    unsuppressibleUnits = unsuppressibleUnits.plusMax(iStretchUnits);
+                    unsuppressibleUnits = unsuppressibleUnits.minusMin(iShrinkUnits);
                     if (!oldListIterator.hasNext()) {
-                        newList.add(new KnuthBox(0,
-                                                 mappingPos,
-                                                 false));
+                        newList.add(new KnuthBox(0, mappingPos, false));
                         //log.debug("        box 0");
                     }
                 }
@@ -1583,7 +1580,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                     newList.add(new KnuthGlue(0,
                                               uStretchChange * bpUnit,
                                               uShrinkChange * bpUnit,
-                                              LINE_NUMBER_ADJUSTMENT,
+                                              Adjustment.LINE_NUMBER_ADJUSTMENT,
                                               mappingPos,
                                               false));
                     newList.add(new KnuthPenalty(uLengthChange * bpUnit,
@@ -1591,7 +1588,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                     newList.add(new KnuthGlue(0,
                                               -uStretchChange * bpUnit,
                                               -uShrinkChange * bpUnit,
-                                              LINE_NUMBER_ADJUSTMENT,
+                                              Adjustment.LINE_NUMBER_ADJUSTMENT,
                                               mappingPos,
                                               false));
                     //log.debug("        PENALTY");
@@ -1612,7 +1609,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             }
 
             if (element.isPenalty()) {
-                lengthBeforeBreak.add(new MinOptMax(-element.getWidth()));
+                lengthBeforeBreak = lengthBeforeBreak.minus(element.getWidth());
             }
 
         }
@@ -1637,13 +1634,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
             KnuthBox wrongBox = (KnuthBox) newList.removeFirst();
             // if this paragraph is at the top of a page, the space before
             // must be ignored; compute the length change
-            int decreasedLength = (neededUnits(totalLength.opt)
-                                   - neededUnits(totalLength.opt - adjustedSpaceBefore))
+            int decreasedLength = (neededUnits(totalLength.getOpt())
+                                   - neededUnits(totalLength.getOpt() - adjustedSpaceBefore))
                                   * bpUnit;
             // insert the correct elements
             newList.addFirst(new KnuthBox(wrongBox.getWidth() - decreasedLength,
                                           wrongBox.getPosition(), false));
-            newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT,
+            newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, Adjustment.SPACE_BEFORE_ADJUSTMENT,
                                            wrongBox.getPosition(), false));
             //log.debug("        rimosso box " + neededUnits(wrongBox.getWidth()));
             //log.debug("        aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
@@ -1673,8 +1670,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
 
             // if this paragraph is at the bottom of a page, the space after
             // must be ignored; compute the length change
-            int decreasedLength = (neededUnits(totalLength.opt)
-                                   - neededUnits(totalLength.opt - adjustedSpaceAfter))
+            int decreasedLength = (neededUnits(totalLength.getOpt())
+                                   - neededUnits(totalLength.getOpt() - adjustedSpaceAfter))
                                   * bpUnit;
             // insert the correct box
             newList.addLast(new KnuthBox(wrongBox.getWidth() - decreasedLength,
@@ -1684,7 +1681,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
                 newList.addAll(preserveList);
             }
             // insert the correct glue
-            newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT,
+            newList.addLast(new KnuthGlue(decreasedLength, 0, 0, Adjustment.SPACE_AFTER_ADJUSTMENT,
                                           wrongBox.getPosition(), false));
             //log.debug("        rimosso box " + neededUnits(wrongBox.getWidth()));
             //log.debug("        aggiunto box " + neededUnits(
@@ -1773,8 +1770,7 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
      */
     protected void wrapPositionElement(ListElement el, List targetList, boolean force) {
         if (force || el.getLayoutManager() != this) {
-            el.setPosition(notifyPos(new NonLeafPosition(this,
-                    el.getPosition())));
+            el.setPosition(notifyPos(new NonLeafPosition(this, el.getPosition())));
         }
         targetList.add(el);
     }
index 28820224a4ab86908e0cc166889ce63fa50a23d4..5236c9234af6cbb23426752dfb849b4e3e9d4809 100644 (file)
@@ -41,7 +41,7 @@ public abstract class BorderOrPaddingElement extends UnresolvedListElementWithLe
             RelSide side,
             boolean isFirst, boolean isLast, PercentBaseContext context) {
         super(position,
-                new MinOptMax(condLength.getLength().getValue(context)), side,
+                MinOptMax.getInstance(condLength.getLength().getValue(context)), side,
                         condLength.isDiscard(), isFirst, isLast);
     }
 
index ca11d27c242784a36092df7b7d4392d29406c52e..6a843ac63994f3de3b859483aac897cdeb406a1a 100644 (file)
@@ -43,7 +43,7 @@ public final class ElementListUtils {
      * @return true if the opt constraint is bigger than the list contents
      */
     public static boolean removeLegalBreaks(List elements, MinOptMax constraint) {
-        return removeLegalBreaks(elements, constraint.opt);
+        return removeLegalBreaks(elements, constraint.getOpt());
     }
 
     /**
@@ -132,7 +132,7 @@ public final class ElementListUtils {
                     }
                 } else if (el instanceof UnresolvedListElementWithLength) {
                     UnresolvedListElementWithLength uel = (UnresolvedListElementWithLength)el;
-                    len += uel.getLength().opt;
+                    len += uel.getLength().getOpt();
                 }
             } else {
                 KnuthElement kel = (KnuthElement)el;
@@ -240,4 +240,4 @@ public final class ElementListUtils {
         return prevBreak;
     }
 
-}
\ No newline at end of file
+}
index affa75abbcf9b770237e916513ee10f4ce6c0302..4f6cfa9d50344eeb82b3fcd6f25b7c600905b4f3 100644 (file)
@@ -83,7 +83,7 @@ public class FootnoteBodyLayoutManager extends BlockStackingLayoutManager {
     /** {@inheritDoc} */
     public void addChildArea(Area childArea) {
         childArea.setAreaClass(Area.CLASS_FOOTNOTE);
-        parentLM.addChildArea(childArea);
+        parentLayoutManager.addChildArea(childArea);
     }
 
     /** @return the FootnoteBody node */
index 1aa22ea3ec0a4dbd5e9d2200d92f307231d08d76..a7fc5bb72cc586358ca9a832415eb9216b395a3f 100644 (file)
@@ -41,30 +41,32 @@ public class KnuthBlockBox extends KnuthBox {
 
     /**
      * Creates a new box.
-     * @param w block progression dimension of this box
-     * @param range min, opt, max inline progression dimension of this box
-     * @param bpdim natural width of the line represented by this box.
-     * @param pos the Position stored in this box
-     * @param bAux is this box auxiliary?
+     *
+     * @param width     block progression dimension of this box
+     * @param range     min, opt, max inline progression dimension of this box
+     * @param bpdim     natural width of the line represented by this box.
+     * @param pos       the Position stored in this box
+     * @param auxiliary is this box auxiliary?
      */
-    public KnuthBlockBox(int w, MinOptMax range, int bpdim, Position pos, boolean bAux) {
-        super(w, pos, bAux);
-        ipdRange = (MinOptMax) range.clone();
+    public KnuthBlockBox(int width, MinOptMax range, int bpdim, Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
+        ipdRange = range;
         bpd = bpdim;
         footnoteList = new LinkedList();
     }
 
     /**
      * Creates a new box.
-     * @param w block progression dimension of this box
-     * @param list footnotes cited by elements in this box. The list contains the
-     * corresponding FootnoteBodyLayoutManagers
-     * @param pos the Position stored in this box
-     * @param bAux is this box auxiliary?
+     *
+     * @param width     block progression dimension of this box
+     * @param list      footnotes cited by elements in this box. The list contains the corresponding
+     *                  FootnoteBodyLayoutManagers
+     * @param pos       the Position stored in this box
+     * @param auxiliary is this box auxiliary?
      */
-    public KnuthBlockBox(int w, List list, Position pos, boolean bAux) {
-        super(w, pos, bAux);
-        ipdRange = new MinOptMax(0);
+    public KnuthBlockBox(int width, List list, Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
+        ipdRange = MinOptMax.ZERO;
         bpd = 0;
         footnoteList = new LinkedList(list);
     }
@@ -85,6 +87,7 @@ public class KnuthBlockBox extends KnuthBox {
 
     /**
      * Adds the given list of Knuth elements to this box' list of elements.
+     *
      * @param list elements corresponding to a footnote body
      */
     public void addElementList(List list) {
@@ -96,8 +99,8 @@ public class KnuthBlockBox extends KnuthBox {
 
     /**
      * Returns the list of Knuth sequences registered by this box.
-     * @return a list of KnuthElement sequences corresponding to footnotes cited in this
-     * box
+     *
+     * @return a list of KnuthElement sequences corresponding to footnotes cited in this box
      */
     public List getElementLists() {
         return elementLists;
@@ -107,12 +110,13 @@ public class KnuthBlockBox extends KnuthBox {
      * @return the inline progression dimension of this box.
      */
     public MinOptMax getIPDRange() {
-        return (MinOptMax) ipdRange.clone();
+        return ipdRange;
     }
 
     /**
-     * Returns the natural width (without stretching nor shrinking) of the line
-     * represented by this box.
+     * Returns the natural width (without stretching nor shrinking) of the line represented by this
+     * box.
+     *
      * @return the line width
      */
     public int getBPD() {
index d7615dda1bae22cb828c519b0f3d29aa18f8a7ef..a1d8c095cf364218affa387e4ca11d462d38acf7 100644 (file)
@@ -35,7 +35,7 @@ package org.apache.fop.layoutmgr;
 public class KnuthBox extends KnuthElement {
 
     /**
-     * Create a new KnuthBox.
+     * Creates a new <code>KnuthBox</code>.
      *
      * @param width    the width of this box
      * @param pos  the Position stored in this box
index e8ca6d85b6e456c987f32919057a1b1bc5e8e405..acd95a7d679f4c573742fd7883b628d9e5d8db78 100644 (file)
@@ -36,8 +36,7 @@ public abstract class KnuthElement extends ListElement {
     private boolean auxiliary;
 
     /**
-     * Create a new KnuthElement.
-     * This class being abstract, this can be called only by subclasses.
+     * Creates a new <code>KnuthElement</code>.
      *
      * @param width    the width of this element
      * @param pos  the Position stored in this element
index 7533a411795db50a97a53e9c2c6c128551aaef0c..2efea0e61eb87f09cd5b9b8d57548d05955a66e8 100644 (file)
@@ -19,6 +19,8 @@
 
 package org.apache.fop.layoutmgr;
 
+import org.apache.fop.traits.MinOptMax;
+
 /**
  * An instance of this class represents a piece of content with adjustable
  * width: for example a space between words of justified text.
@@ -47,31 +49,49 @@ package org.apache.fop.layoutmgr;
  */
 public class KnuthGlue extends KnuthElement {
 
-    private int stretchability;
-    private int shrinkability;
-    private int adjustmentClass = -1;
+    private final int stretch;
+    private final int shrink;
+    private final Adjustment adjustmentClass;
+
+    /**
+     * Creates a new <code>KnuthGlue</code>.
+     *
+     * @param minOptMax a <code>MinOptMax</code> where the {@link MinOptMax#getOpt() opt-value} is
+     *                  mapped to the width, the {@link MinOptMax#getStretch()
+     *                  stretchability} is mapped to the stretchability and the the {@link
+     *                  MinOptMax#getShrink() shrinkability} is mapped to the shrinkability
+     * @param pos       the Position stored in this glue
+     * @param auxiliary is this glue auxiliary?
+     */
+    public KnuthGlue(MinOptMax minOptMax, Position pos, boolean auxiliary) {
+        super(minOptMax.getOpt(), pos, auxiliary);
+        this.stretch = minOptMax.getStretch();
+        this.shrink = minOptMax.getShrink();
+        this.adjustmentClass = Adjustment.NO_ADJUSTMENT;
+    }
 
     /**
-     * Create a new KnuthGlue.
+     * Creates a new <code>KnuthGlue</code>.
      *
-     * @param width the width of this glue
-     * @param stretchability the stretchability of this glue
-     * @param shrinkability the shrinkability of this glue
-     * @param pos the Position stored in this glue
+     * @param width     the width of this glue
+     * @param stretch   the stretchability of this glue
+     * @param shrink    the shrinkability of this glue
+     * @param pos       the Position stored in this glue
      * @param auxiliary is this glue auxiliary?
      */
-    public KnuthGlue(int width, int stretchability, int shrinkability, Position pos,
+    public KnuthGlue(int width, int stretch, int shrink, Position pos,
                      boolean auxiliary) {
         super(width, pos, auxiliary);
-        this.stretchability = stretchability;
-        this.shrinkability = shrinkability;
+        this.stretch = stretch;
+        this.shrink = shrink;
+        this.adjustmentClass = Adjustment.NO_ADJUSTMENT;
     }
 
-    public KnuthGlue(int width, int stretchability, int shrinkability, int adjustmentClass,
+    public KnuthGlue(int width, int stretch, int shrink, Adjustment adjustmentClass,
                      Position pos, boolean auxiliary) {
         super(width, pos, auxiliary);
-        this.stretchability = stretchability;
-        this.shrinkability = shrinkability;
+        this.stretch = stretch;
+        this.shrink = shrink;
         this.adjustmentClass = adjustmentClass;
     }
 
@@ -82,16 +102,16 @@ public class KnuthGlue extends KnuthElement {
 
     /** @return the stretchability of this glue. */
     public int getStretch() {
-        return stretchability;
+        return stretch;
     }
 
     /** @return the shrinkability of this glue. */
     public int getShrink() {
-        return shrinkability;
+        return shrink;
     }
 
     /** @return the adjustment class (or role) of this glue. */
-    public int getAdjustmentClass() {
+    public Adjustment getAdjustmentClass() {
         return adjustmentClass;
     }
 
@@ -105,7 +125,7 @@ public class KnuthGlue extends KnuthElement {
         buffer.append(" w=").append(getWidth());
         buffer.append(" stretch=").append(getStretch());
         buffer.append(" shrink=").append(getShrink());
-        if (getAdjustmentClass() >= 0) {
+        if (!getAdjustmentClass().equals(Adjustment.NO_ADJUSTMENT)) {
             buffer.append(" adj-class=").append(getAdjustmentClass());
         }
         return buffer.toString();
index 81726e57bdf04cf6452ea8c38fc4310f06e7915a..752ffd628b4528d884cd8d2c8240bbef332733c7 100644 (file)
@@ -173,7 +173,7 @@ public class LayoutContext {
     public LayoutContext(int flags) {
         this.flags = flags;
         this.refIPD = 0;
-        stackLimitBP = new MinOptMax(0);
+        stackLimitBP = MinOptMax.ZERO;
         leadingSpace = null;
         trailingSpace = null;
     }
index 8b2a5f4bc8e9ff727d620ef45af04497a909738a..e1d5b2aaa9ec01c7baae49ce17cd24847c44ba5e 100644 (file)
@@ -23,8 +23,8 @@ public class LeafPosition extends Position {
 
     private int leafPos;
 
-    public LeafPosition(LayoutManager lm, int pos) {
-        super(lm);
+    public LeafPosition(LayoutManager layoutManager, int pos) {
+        super(layoutManager);
         leafPos = pos;
     }
 
diff --git a/src/java/org/apache/fop/layoutmgr/MinOptMaxUtil.java b/src/java/org/apache/fop/layoutmgr/MinOptMaxUtil.java
deleted file mode 100644 (file)
index f029d90..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.datatypes.PercentBaseContext;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.properties.LengthRangeProperty;
-import org.apache.fop.traits.MinOptMax;
-
-/**
- * Utilities for MinOptMax and LengthRangeProperty.
- */
-public class MinOptMaxUtil {
-
-    /**
-     * Restricts a MinOptMax using the values from a LengthRangeProperty.
-     * @param mom MinOptMax to restrict
-     * @param lr restricting source
-     * @param context Percentage evaluation context
-     */
-    public static void restrict(MinOptMax mom, LengthRangeProperty lr,
-                                PercentBaseContext context) {
-        if (lr.getEnum() != Constants.EN_AUTO) {
-            if (lr.getMinimum(context).getEnum() != Constants.EN_AUTO) {
-                int min = lr.getMinimum(context).getLength().getValue(context);
-                if (min > mom.min) {
-                    mom.min = min;
-                    fixAfterMinChanged(mom);
-                }
-            }
-            if (lr.getMaximum(context).getEnum() != Constants.EN_AUTO) {
-                int max = lr.getMaximum(context).getLength().getValue(context);
-                if (max < mom.max) {
-                    mom.max = max;
-                    if (mom.max < mom.opt) {
-                        mom.opt = mom.max;
-                        mom.min = mom.opt;
-                    }
-                }
-            }
-            if (lr.getOptimum(context).getEnum() != Constants.EN_AUTO) {
-                int opt = lr.getOptimum(context).getLength().getValue(context);
-                if (opt > mom.min) {
-                    mom.opt = opt;
-                    if (mom.opt > mom.max) {
-                        mom.max = mom.opt;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Extends the minimum length to the given length if necessary, and adjusts opt and
-     * max accordingly.
-     *
-     * @param mom the min/opt/max trait
-     * @param len the new minimum length
-     */
-    public static void extendMinimum(MinOptMax mom, int len) {
-        if (mom.min < len) {
-            mom.min = len;
-            mom.opt = Math.max(mom.min, mom.opt);
-            mom.max = Math.max(mom.opt, mom.max);
-        }
-    }
-
-    /**
-     * After a calculation on a MinOptMax, this can be called to set opt to
-     * a new effective value.
-     * @param mom MinOptMax to adjust
-     */
-    public static void fixAfterMinChanged(MinOptMax mom) {
-        if (mom.min > mom.opt) {
-            mom.opt = mom.min;
-            if (mom.opt > mom.max) {
-                mom.max = mom.opt;
-            }
-        }
-    }
-
-    /**
-     * Converts a LengthRangeProperty to a MinOptMax.
-     * @param prop LengthRangeProperty
-     * @param context Percentage evaluation context
-     * @return the requested MinOptMax instance
-     */
-    public static MinOptMax toMinOptMax(LengthRangeProperty prop, PercentBaseContext context) {
-        int min = prop.getMinimum(context).isAuto() ? 0
-                : prop.getMinimum(context).getLength().getValue(context);
-        int opt = prop.getOptimum(context).isAuto() ? min
-                : prop.getOptimum(context).getLength().getValue(context);
-        int max = prop.getMaximum(context).isAuto() ? Integer.MAX_VALUE
-                : prop.getMaximum(context).getLength().getValue(context);
-        return new MinOptMax(min, opt, max);
-    }
-
-}
index 86c3fccf8778f18fc20a2887941d8cf7f0a32f82..134e69f31298cde0a5305f235befc4339d338c3b 100644 (file)
@@ -19,7 +19,6 @@
 
 package org.apache.fop.layoutmgr;
 
-import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
 
@@ -204,7 +203,7 @@ public class PageBreaker extends AbstractBreaker {
                         pslm, footnoteSeparator, separatorArea);
             footnoteSeparatorLM.doLayout();
 
-            footnoteSeparatorLength = new MinOptMax(separatorArea.getBPD());
+            footnoteSeparatorLength = MinOptMax.getInstance(separatorArea.getBPD());
         }
     }
 
index cab68a13fb6ca5deaf3ef85a4f0499dd4ec32e3c..8f60e51b7dda58881bcf2f4679901b5937ad00b9 100644 (file)
@@ -116,7 +116,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
         this.pageProvider = pageProvider;
         this.layoutListener = layoutListener;
         best = new BestPageRecords();
-        this.footnoteSeparatorLength = (MinOptMax) footnoteSeparatorLength.clone();
+        this.footnoteSeparatorLength = footnoteSeparatorLength;
         this.autoHeight = autoHeight;
         this.favorSinglePart = favorSinglePart;
     }
@@ -483,7 +483,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
             if (allFootnotes > 0) {
                 // this page contains some footnote citations
                 // add the footnote separator width
-                actualWidth += footnoteSeparatorLength.opt;
+                actualWidth += footnoteSeparatorLength.getOpt();
                 if (actualWidth + allFootnotes <= getLineWidth(activeNode.line)) {
                     // there is enough space to insert all footnotes:
                     // add the whole allFootnotes length
@@ -757,7 +757,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
             int maxAdjustment = totalStretch - activeNode.totalStretch;
             // add the footnote separator stretch if some footnote content will be added
             if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) {
-                maxAdjustment += footnoteSeparatorLength.max - footnoteSeparatorLength.opt;
+                maxAdjustment += footnoteSeparatorLength.getStretch();
             }
             if (maxAdjustment > 0) {
                 return (double) difference / maxAdjustment;
@@ -768,7 +768,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
             int maxAdjustment = totalShrink - activeNode.totalShrink;
             // add the footnote separator shrink if some footnote content will be added
             if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) {
-                maxAdjustment += footnoteSeparatorLength.opt - footnoteSeparatorLength.min;
+                maxAdjustment += footnoteSeparatorLength.getShrink();
             }
             if (maxAdjustment > 0) {
                 return (double) difference / maxAdjustment;
index 820cf6506b76a218b070ca3530024ea06c398b8b..6590d3a2a21bb9f78549db4dc37f88298649ff0f 100644 (file)
@@ -40,13 +40,10 @@ public class SpaceElement extends UnresolvedListElementWithLength {
      * @param isLast true if this is a space-after of the last area generated.
      * @param context the property evaluation context
      */
-    public SpaceElement(Position position, SpaceProperty space, RelSide side,
-            boolean isFirst, boolean isLast,
-            PercentBaseContext context) {
-        super(position,
-                MinOptMaxUtil.toMinOptMax(
-                        space.getSpace().getLengthRange(),
-                context), side, space.isDiscard(), isFirst, isLast);
+    public SpaceElement(Position position, SpaceProperty space, RelSide side, boolean isFirst,
+                        boolean isLast, PercentBaseContext context) {
+        super(position, space.getSpace().getLengthRange().toMinOptMax(context), side,
+                space.isDiscard(), isFirst, isLast);
         int en = space.getSpace().getPrecedence().getEnum();
         if (en == Constants.EN_FORCE) {
             this.precedence = Integer.MAX_VALUE;
index ff464ce6ad1c2618136faba8dc000b0bf333b639..6dbf107f3db2f37ba0e2974cb82e79ce73b599c4 100644 (file)
@@ -152,7 +152,7 @@ public class SpaceResolver {
     }
 
     private void removeConditionalBorderAndPadding(
-                UnresolvedListElement[] elems, MinOptMax[] lengths, boolean reverse) {
+            UnresolvedListElement[] elems, MinOptMax[] lengths, boolean reverse) {
         for (int i = 0; i < elems.length; i++) {
             int effIndex;
             if (reverse) {
@@ -176,7 +176,7 @@ public class SpaceResolver {
     }
 
     private void performSpaceResolutionRule1(UnresolvedListElement[] elems, MinOptMax[] lengths,
-                    boolean reverse) {
+            boolean reverse) {
         for (int i = 0; i < elems.length; i++) {
             int effIndex;
             if (reverse) {
@@ -274,7 +274,7 @@ public class SpaceResolver {
                 }
                 lengths[i] = null;
             } else {
-                greatestOptimum = Math.max(greatestOptimum, space.getLength().opt);
+                greatestOptimum = Math.max(greatestOptimum, space.getLength().getOpt());
                 remaining++;
             }
         }
@@ -291,7 +291,7 @@ public class SpaceResolver {
                 continue;
             }
             space = (SpaceElement)elems[i];
-            if (space.getLength().opt < greatestOptimum) {
+            if (space.getLength().getOpt() < greatestOptimum) {
                 if (log.isDebugEnabled()) {
                     log.debug("Nulling space-specifier with smaller optimum length "
                             + "using 4.3.1, rule 3: "
@@ -313,8 +313,8 @@ public class SpaceResolver {
                 continue;
             }
             space = (SpaceElement)elems[i];
-            min = Math.max(min, space.getLength().min);
-            max = Math.min(max, space.getLength().max);
+            min = Math.max(min, space.getLength().getMin());
+            max = Math.min(max, space.getLength().getMax());
             if (remaining > 1) {
                 if (log.isDebugEnabled()) {
                     log.debug("Nulling non-last space-specifier using 4.3.1, rule 3, second part: "
@@ -323,8 +323,7 @@ public class SpaceResolver {
                 lengths[i] = null;
                 remaining--;
             } else {
-                lengths[i].min = min;
-                lengths[i].max = max;
+                lengths[i] = MinOptMax.getInstance(min, lengths[i].getOpt(), max);
             }
         }
 
@@ -409,54 +408,27 @@ public class SpaceResolver {
     }
 
     private MinOptMax sum(MinOptMax[] lengths) {
-        MinOptMax sum = new MinOptMax();
+        MinOptMax sum = MinOptMax.ZERO;
         for (int i = 0; i < lengths.length; i++) {
             if (lengths[i] != null) {
-                sum.add(lengths[i]);
+                sum = sum.plus(lengths[i]);
             }
         }
         return sum;
     }
 
     private void generate(ListIterator iter) {
-        MinOptMax noBreakLength = new MinOptMax();
-        MinOptMax glue1; //space before break possibility if break occurs
-        //MinOptMax glue2; //difference between glue 1 and 3 when no break occurs
-        MinOptMax glue3; //space after break possibility if break occurs
-        glue1 = sum(firstPartLengths);
-        glue3 = sum(secondPartLengths);
-        noBreakLength = sum(noBreakLengths);
-
-        //This doesn't produce the right glue2
-        //glue2 = new MinOptMax(noBreakLength);
-        //glue2.subtract(glue1);
-        //glue2.subtract(glue3);
-
-        int glue2w = noBreakLength.opt - glue1.opt - glue3.opt;
-        int glue2stretch = (noBreakLength.max - noBreakLength.opt);
-        int glue2shrink = (noBreakLength.opt - noBreakLength.min);
-        glue2stretch -= glue1.max - glue1.opt;
-        glue2stretch -= glue3.max - glue3.opt;
-        glue2shrink -= glue1.opt - glue1.min;
-        glue2shrink -= glue3.opt - glue3.min;
+        MinOptMax spaceBeforeBreak = sum(firstPartLengths);
+        MinOptMax spaceAfterBreak = sum(secondPartLengths);
 
         boolean hasPrecedingNonBlock = false;
-        if (log.isDebugEnabled()) {
-            log.debug("noBreakLength=" + noBreakLength
-                    + ", glue1=" + glue1
-                    + ", glue2=" + glue2w + "+" + glue2stretch + "-" + glue2shrink
-                    + ", glue3=" + glue3);
-        }
         if (breakPoss != null) {
-            boolean forcedBreak = breakPoss.isForcedBreak();
-            if (glue1.isNonZero()) {
-                iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE,
-                        false, (Position)null, true));
-                iter.add(new KnuthGlue(glue1.opt, glue1.max - glue1.opt, glue1.opt - glue1.min,
-                        (Position)null, true));
-                if (forcedBreak) {
+            if (spaceBeforeBreak.isNonZero()) {
+                iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false, null, true));
+                iter.add(new KnuthGlue(spaceBeforeBreak, null, true));
+                if (breakPoss.isForcedBreak()) {
                     //Otherwise, the preceding penalty and glue will be cut off
-                    iter.add(new KnuthBox(0, (Position)null, true));
+                    iter.add(new KnuthBox(0, null, true));
                 }
             }
             iter.add(new KnuthPenalty(breakPoss.getPenaltyWidth(), breakPoss.getPenaltyValue(),
@@ -465,32 +437,38 @@ public class SpaceResolver {
             if (breakPoss.getPenaltyValue() <= -KnuthPenalty.INFINITE) {
                 return; //return early. Not necessary (even wrong) to add additional elements
             }
-            if (glue2w != 0 || glue2stretch != 0 || glue2shrink != 0) {
-                iter.add(new KnuthGlue(glue2w, glue2stretch, glue2shrink,
-                        (Position)null, true));
+
+            // No break
+            // TODO: We can't use a MinOptMax for glue2, because min <= opt <= max is not always true - why?
+            MinOptMax noBreakLength = sum(noBreakLengths);
+            MinOptMax spaceSum = spaceBeforeBreak.plus(spaceAfterBreak);
+            int glue2width = noBreakLength.getOpt() - spaceSum.getOpt();
+            int glue2stretch = noBreakLength.getStretch() - spaceSum.getStretch();
+            int glue2shrink = noBreakLength.getShrink() - spaceSum.getShrink();
+
+            if (glue2width != 0 || glue2stretch != 0 || glue2shrink != 0) {
+                iter.add(new KnuthGlue(glue2width, glue2stretch, glue2shrink, null, true));
             }
         } else {
-            if (glue1.isNonZero()) {
-                throw new IllegalStateException("glue1 should be 0 in this case");
+            if (spaceBeforeBreak.isNonZero()) {
+                throw new IllegalStateException("spaceBeforeBreak should be 0 in this case");
             }
         }
         Position pos = null;
         if (breakPoss == null) {
             pos = new SpaceHandlingPosition(this);
         }
-        if (glue3.isNonZero() || pos != null) {
+        if (spaceAfterBreak.isNonZero() || pos != null) {
             iter.add(new KnuthBox(0, pos, true));
         }
-        if (glue3.isNonZero()) {
-            iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE,
-                    false, (Position)null, true));
-            iter.add(new KnuthGlue(glue3.opt, glue3.max - glue3.opt, glue3.opt - glue3.min,
-                    (Position)null, true));
+        if (spaceAfterBreak.isNonZero()) {
+            iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false, null, true));
+            iter.add(new KnuthGlue(spaceAfterBreak, null, true));
             hasPrecedingNonBlock = true;
         }
         if (isLast && hasPrecedingNonBlock) {
             //Otherwise, the preceding penalty and glue will be cut off
-            iter.add(new KnuthBox(0, (Position)null, true));
+            iter.add(new KnuthBox(0, null, true));
         }
     }
 
@@ -608,9 +586,7 @@ public class SpaceResolver {
 
         /** {@inheritDoc} */
         public String toString() {
-            StringBuffer sb = new StringBuffer();
-            sb.append("SpaceHandlingPosition");
-            return sb.toString();
+            return "SpaceHandlingPosition";
         }
     }
 
@@ -741,5 +717,4 @@ public class SpaceResolver {
     }
 
 
-
 }
index 62a0661213310c625fe5066a005f8619a97bf463..140d90bb86964cce4819ce9987821bcc5b3e2dda 100644 (file)
@@ -31,12 +31,10 @@ import org.apache.fop.traits.MinOptMax;
  */
 public class SpaceSpecifier implements Cloneable {
 
-
     private boolean startsReferenceArea;
     private boolean hasForcing = false;
     private List spaceVals = new ArrayList();
 
-
     /**
      * Creates a new SpaceSpecifier.
      * @param startsReferenceArea true if it starts a new reference area
@@ -76,7 +74,7 @@ public class SpaceSpecifier implements Cloneable {
      * @return true if any space-specifiers have been added.
      */
     public boolean hasSpaces() {
-        return (spaceVals.size() > 0);
+        return !spaceVals.isEmpty();
     }
 
     /**
@@ -84,24 +82,22 @@ public class SpaceSpecifier implements Cloneable {
      * area, and the added space is conditional, and there are no
      * non-conditional values in the sequence yet, then ignore it. Otherwise
      * add it to the sequence.
+     *
+     * @param space the space to add.
      */
-    public void addSpace(SpaceVal moreSpace) {
-        if (!startsReferenceArea
-                || !moreSpace.isConditional()
-                || !spaceVals.isEmpty()) {
-            if (moreSpace.isForcing()) {
+    public void addSpace(SpaceVal space) {
+        if (!startsReferenceArea || !space.isConditional() || hasSpaces()) {
+            if (space.isForcing()) {
                 if (!hasForcing) {
                     // Remove all other values (must all be non-forcing)
                     spaceVals.clear();
                     hasForcing = true;
                 }
-                spaceVals.add(moreSpace);
+                spaceVals.add(space);
             } else if (!hasForcing) {
                 // Don't bother adding all 0 space-specifier if not forcing
-                if (moreSpace.getSpace().min != 0
-                        || moreSpace.getSpace().opt != 0
-                        || moreSpace.getSpace().max != 0) {
-                    spaceVals.add(moreSpace);
+                if (space.getSpace().isNonZero()) {
+                    spaceVals.add(space);
                 }
             }
         }
@@ -109,11 +105,11 @@ public class SpaceSpecifier implements Cloneable {
 
 
     /**
-     * Resolve the current sequence of space-specifiers, accounting for
-     * forcing values.
-     * @param endsReferenceArea True if the sequence should be resolved
-     * at the trailing edge of reference area.
-     * @return The resolved value as a min/opt/max triple.
+     * Resolve the current sequence of space-specifiers, accounting for forcing values.
+     *
+     * @param endsReferenceArea whether the sequence should be resolved at the trailing edge of
+     *                          reference area.
+     * @return the resolved value as a min/opt/max triple.
      */
     public MinOptMax resolve(boolean endsReferenceArea) {
         int lastIndex = spaceVals.size();
@@ -127,24 +123,30 @@ public class SpaceSpecifier implements Cloneable {
                 }
             }
         }
-        MinOptMax resolvedSpace = new MinOptMax(0);
+        MinOptMax resolvedSpace = MinOptMax.ZERO;
         int maxPrecedence = -1;
         for (int index = 0; index < lastIndex; index++) {
             SpaceVal spaceVal = (SpaceVal) spaceVals.get(index);
+            MinOptMax space = spaceVal.getSpace();
             if (hasForcing) {
-                resolvedSpace.add(spaceVal.getSpace());
-            } else if (spaceVal.getPrecedence() > maxPrecedence) {
-                maxPrecedence = spaceVal.getPrecedence();
-                resolvedSpace = spaceVal.getSpace();
-            } else if (spaceVal.getPrecedence() == maxPrecedence) {
-                if (spaceVal.getSpace().opt > resolvedSpace.opt) {
-                    resolvedSpace = spaceVal.getSpace();
-                } else if (spaceVal.getSpace().opt == resolvedSpace.opt) {
-                    if (resolvedSpace.min < spaceVal.getSpace().min) {
-                        resolvedSpace.min = spaceVal.getSpace().min;
-                    }
-                    if (resolvedSpace.max > spaceVal.getSpace().max) {
-                        resolvedSpace.max = spaceVal.getSpace().max;
+                resolvedSpace = resolvedSpace.plus(space);
+            } else {
+                int precedence = spaceVal.getPrecedence();
+                if (precedence > maxPrecedence) {
+                    maxPrecedence = precedence;
+                    resolvedSpace = space;
+                } else if (precedence == maxPrecedence) {
+                    if (space.getOpt() > resolvedSpace.getOpt()) {
+                        resolvedSpace = space;
+                    } else if (space.getOpt() == resolvedSpace.getOpt()) {
+                        if (resolvedSpace.getMin() < space.getMin()) {
+                            resolvedSpace = MinOptMax.getInstance(space.getMin(),
+                                    resolvedSpace.getOpt(), resolvedSpace.getMax());
+                        }
+                        if (resolvedSpace.getMax() > space.getMax()) {
+                            resolvedSpace = MinOptMax.getInstance(resolvedSpace.getMin(),
+                                    resolvedSpace.getOpt(), space.getMax());
+                        }
                     }
                 }
             }
@@ -154,8 +156,7 @@ public class SpaceSpecifier implements Cloneable {
     }
 
     public String toString() {
-        return "Space Specifier (resolved at begin/end of ref. area:):\n" +
-            resolve(false).toString() + "\n" +
-            resolve(true).toString();
+        return "Space Specifier (resolved at begin/end of ref. area:):\n"
+                + resolve(false) + "\n" + resolve(true);
     }
 }
index d062ba2ca4157bf349b133408e42c9d8fa083917..911b6dcc613ef1970fb0af80c4b25bca43987cde 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Trait;
 import org.apache.fop.datatypes.LengthBase;
@@ -29,7 +30,6 @@ import org.apache.fop.datatypes.SimplePercentBaseContext;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonMarginBlock;
-import org.apache.fop.fo.properties.CommonMarginBlock;
 import org.apache.fop.fo.properties.CommonTextDecoration;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 import org.apache.fop.fonts.Font;
@@ -46,11 +46,12 @@ public class TraitSetter {
 
     /**
      * Sets border and padding traits on areas.
-     * @param area area to set the traits on
-     * @param bpProps border and padding properties
+     *
+     * @param area      area to set the traits on
+     * @param bpProps   border and padding properties
      * @param bNotFirst True if the area is not the first area
-     * @param bNotLast True if the area is not the last area
-     * @param context Property evaluation context
+     * @param bNotLast  True if the area is not the last area
+     * @param context   Property evaluation context
      */
     public static void setBorderPaddingTraits(Area area,
             CommonBorderPaddingBackground bpProps, boolean bNotFirst, boolean bNotLast,
@@ -74,27 +75,28 @@ public class TraitSetter {
         }
 
         addBorderTrait(area, bpProps, bNotFirst,
-                       CommonBorderPaddingBackground.START,
-                       BorderProps.SEPARATE, Trait.BORDER_START);
+                CommonBorderPaddingBackground.START,
+                BorderProps.SEPARATE, Trait.BORDER_START);
 
         addBorderTrait(area, bpProps, bNotLast,
-                       CommonBorderPaddingBackground.END,
-                       BorderProps.SEPARATE, Trait.BORDER_END);
+                CommonBorderPaddingBackground.END,
+                BorderProps.SEPARATE, Trait.BORDER_END);
 
         addBorderTrait(area, bpProps, false,
-                       CommonBorderPaddingBackground.BEFORE,
-                       BorderProps.SEPARATE, Trait.BORDER_BEFORE);
+                CommonBorderPaddingBackground.BEFORE,
+                BorderProps.SEPARATE, Trait.BORDER_BEFORE);
 
         addBorderTrait(area, bpProps, false,
-                       CommonBorderPaddingBackground.AFTER,
-                       BorderProps.SEPARATE, Trait.BORDER_AFTER);
+                CommonBorderPaddingBackground.AFTER,
+                BorderProps.SEPARATE, Trait.BORDER_AFTER);
     }
 
     /**
      * Sets border traits on an area.
-     * @param area area to set the traits on
+     *
+     * @param area    area to set the traits on
      * @param bpProps border and padding properties
-     * @param mode the border paint mode (see BorderProps)
+     * @param mode    the border paint mode (see BorderProps)
      */
     private static void addBorderTrait(Area area,
                                        CommonBorderPaddingBackground bpProps,
@@ -103,9 +105,9 @@ public class TraitSetter {
         int iBP = bpProps.getBorderWidth(iSide, bDiscard);
         if (iBP > 0) {
             area.addTrait(oTrait,
-                          new BorderProps(bpProps.getBorderStyle(iSide),
-                                          iBP, bpProps.getBorderColor(iSide),
-                                          mode));
+                    new BorderProps(bpProps.getBorderStyle(iSide),
+                            iBP, bpProps.getBorderColor(iSide),
+                            mode));
         }
     }
 
@@ -119,7 +121,7 @@ public class TraitSetter {
      * @deprecated Call the other addBorders() method and addPadding separately.
      */
     public static void addBorders(Area area, CommonBorderPaddingBackground bordProps,
-                                PercentBaseContext context) {
+                                  PercentBaseContext context) {
         BorderProps bps = getBorderProps(bordProps, CommonBorderPaddingBackground.BEFORE);
         if (bps != null) {
             area.addTrait(Trait.BORDER_BEFORE, bps);
@@ -397,9 +399,9 @@ public class TraitSetter {
                         int imageWidthMpt = back.getImageInfo().getSize().getWidthMpt();
                         int lengthBaseValue = width - imageWidthMpt;
                         SimplePercentBaseContext simplePercentBaseContext
-                            = new SimplePercentBaseContext(context,
-                            LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
-                            lengthBaseValue);
+                                = new SimplePercentBaseContext(context,
+                                LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
+                                lengthBaseValue);
                         int horizontal = backProps.backgroundPositionHorizontal.getValue(
                                 simplePercentBaseContext);
                         back.setHoriz(horizontal);
@@ -421,7 +423,7 @@ public class TraitSetter {
                         int imageHeightMpt = back.getImageInfo().getSize().getHeightMpt();
                         int lengthBaseValue = height - imageHeightMpt;
                         SimplePercentBaseContext simplePercentBaseContext
-                            = new SimplePercentBaseContext(context,
+                                = new SimplePercentBaseContext(context,
                                 LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
                                 lengthBaseValue);
                         int vertical = backProps.backgroundPositionVertical.getValue(
@@ -459,8 +461,8 @@ public class TraitSetter {
         }
 
         int spaceStart = startIndent
-                            - bpProps.getBorderStartWidth(false)
-                            - bpProps.getPaddingStart(false, context);
+                - bpProps.getBorderStartWidth(false)
+                - bpProps.getPaddingStart(false, context);
         if (spaceStart != 0) {
             area.addTrait(Trait.SPACE_START, new Integer(spaceStart));
         }
@@ -469,8 +471,8 @@ public class TraitSetter {
             area.addTrait(Trait.END_INDENT, new Integer(endIndent));
         }
         int spaceEnd = endIndent
-                            - bpProps.getBorderEndWidth(false)
-                            - bpProps.getPaddingEnd(false, context);
+                - bpProps.getBorderEndWidth(false)
+                - bpProps.getPaddingEnd(false, context);
         if (spaceEnd != 0) {
             area.addTrait(Trait.SPACE_END, new Integer(spaceEnd));
         }
@@ -504,14 +506,15 @@ public class TraitSetter {
     public static int getEffectiveSpace(double adjust, MinOptMax space) {
         if (space == null) {
             return 0;
-        }
-        int sp = space.opt;
-        if (adjust > 0) {
-            sp = sp + (int)(adjust * (space.max - space.opt));
         } else {
-            sp = sp + (int)(adjust * (space.opt - space.min));
+            int spaceOpt = space.getOpt();
+            if (adjust > 0) {
+                spaceOpt += (int) (adjust * space.getStretch());
+            } else {
+                spaceOpt += (int) (adjust * space.getShrink());
+            }
+            return spaceOpt;
         }
-        return sp;
     }
 
     /**
@@ -521,16 +524,17 @@ public class TraitSetter {
      * @param spaceBefore the space-before space specifier
      * @param spaceAfter the space-after space specifier
      */
-    public static void addSpaceBeforeAfter(Area area, double adjust,
-            MinOptMax spaceBefore, MinOptMax spaceAfter) {
-        int space;
-        space = getEffectiveSpace(adjust, spaceBefore);
-        if (space != 0) {
-            area.addTrait(Trait.SPACE_BEFORE, new Integer(space));
-        }
-        space = getEffectiveSpace(adjust, spaceAfter);
-        if (space != 0) {
-            area.addTrait(Trait.SPACE_AFTER, new Integer(space));
+    public static void addSpaceBeforeAfter(Area area, double adjust, MinOptMax spaceBefore,
+                                           MinOptMax spaceAfter) {
+        addSpaceTrait(area, Trait.SPACE_BEFORE, spaceBefore, adjust);
+        addSpaceTrait(area, Trait.SPACE_AFTER, spaceAfter, adjust);
+    }
+
+    private static void addSpaceTrait(Area area, Integer spaceTrait,
+            MinOptMax space, double adjust) {
+        int effectiveSpace = getEffectiveSpace(adjust, space);
+        if (effectiveSpace != 0) {
+            area.addTrait(spaceTrait, new Integer(effectiveSpace));
         }
     }
 
@@ -540,7 +544,7 @@ public class TraitSetter {
      * @param breakBefore the value for break-before
      * @param breakAfter the value for break-after
      */
-    public static void addBreaks(Area area,  int breakBefore, int breakAfter) {
+    public static void addBreaks(Area area, int breakBefore, int breakAfter) {
         /* Currently disabled as these traits are never used by the renderers
         area.addTrait(Trait.BREAK_AFTER, new Integer(breakAfter));
         area.addTrait(Trait.BREAK_BEFORE, new Integer(breakBefore));
@@ -593,7 +597,7 @@ public class TraitSetter {
             area.addTrait(Trait.PTR, ptr);
         }
     }
-    
+
     /**
      * Sets the producer's ID as a trait on the area. This can be used to track back the
      * generating FO node.
index dcd993487f369caaebe30b4f4d1b74aba488c9a6..a19680f51113ec40b45730b71072bdf9eee93497 100644 (file)
@@ -23,6 +23,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.fop.area.Trait;
+import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.fo.flow.Character;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fonts.Font;
@@ -67,14 +68,13 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
         hyphIPD = fobj.getCommonHyphenation().getHyphIPD(font);
         borderProps = fobj.getCommonBorderPaddingBackground();
         setCommonBorderPaddingBackground(borderProps);
-        org.apache.fop.area.inline.TextArea chArea = getCharacterInlineArea(fobj);
+        TextArea chArea = getCharacterInlineArea(fobj);
         chArea.setBaselineOffset(font.getAscender());
         setCurrentArea(chArea);
     }
 
-    private org.apache.fop.area.inline.TextArea getCharacterInlineArea(Character node) {
-        org.apache.fop.area.inline.TextArea text
-            = new org.apache.fop.area.inline.TextArea();
+    private TextArea getCharacterInlineArea(Character node) {
+        TextArea text = new TextArea();
         char ch = node.getCharacter();
         if (CharUtilities.isAnySpace(ch)) {
             // add space unless it's zero-width:
@@ -103,9 +103,9 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
 
         Character fobj = (Character)this.fobj;
 
-        ipd = new MinOptMax(font.getCharWidth(fobj.getCharacter()));
+        ipd = MinOptMax.getInstance(font.getCharWidth(fobj.getCharacter()));
 
-        curArea.setIPD(ipd.opt);
+        curArea.setIPD(ipd.getOpt());
         curArea.setBPD(font.getAscender() - font.getDescender());
 
         TraitSetter.addFontTraits(curArea, font);
@@ -126,16 +126,16 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
         areaInfo = new AreaInfo((short) 0, ipd, false, alignmentContext);
 
         // node is a fo:Character
-        if (letterSpaceIPD.min == letterSpaceIPD.max) {
+        if (letterSpaceIPD.isStiff()) {
             // constant letter space, only return a box
-            seq.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.alignmentContext,
+            seq.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext,
                                         notifyPos(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
-            seq.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.alignmentContext,
+            seq.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext,
                                         notifyPos(new LeafPosition(this, 0)), false));
             seq.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                             new LeafPosition(this, -1), true));
@@ -154,9 +154,8 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
     }
 
     /** {@inheritDoc} */
-    public void getWordChars(StringBuffer sbChars, Position bp) {
-        sbChars.append
-            (((org.apache.fop.area.inline.TextArea) curArea).getText());
+    public String getWordChars(Position pos) {
+        return ((TextArea) curArea).getText();
     }
 
     /** {@inheritDoc} */
@@ -189,10 +188,9 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
 
         addKnuthElementsForBorderPaddingStart(returnList);
 
-        if (letterSpaceIPD.min == letterSpaceIPD.max
-            || areaInfo.iLScount == 0) {
+        if (letterSpaceIPD.isStiff() || areaInfo.iLScount == 0) {
             // constant letter space, or no letter space
-            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt,
+            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(),
                                         areaInfo.alignmentContext,
                                         notifyPos(new LeafPosition(this, 0)), false));
             if (areaInfo.bHyphenated) {
@@ -202,24 +200,17 @@ public class CharacterLayoutManager extends LeafNodeLayoutManager {
             }
         } else {
             // adjustable letter space
-            returnList.add
-                (new KnuthInlineBox(areaInfo.ipdArea.opt
-                              - areaInfo.iLScount * letterSpaceIPD.opt,
-                              areaInfo.alignmentContext,
-                              notifyPos(new LeafPosition(this, 0)), false));
+            returnList.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt()
+                    - areaInfo.iLScount * letterSpaceIPD.getOpt(), areaInfo.alignmentContext,
+                    notifyPos(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, null,
-                                        notifyPos(new LeafPosition(this, -1)), true));
+                    new LeafPosition(this, -1), true));
+            returnList.add(new KnuthGlue(letterSpaceIPD.mult(areaInfo.iLScount),
+                    new LeafPosition(this, -1), true));
+            returnList.add(new KnuthInlineBox(0, null, notifyPos(new LeafPosition(this, -1)), true));
             if (areaInfo.bHyphenated) {
-                returnList.add
-                    (new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true,
-                                      new LeafPosition(this, -1), false));
+                returnList.add(new KnuthPenalty(hyphIPD, KnuthPenalty.FLAGGED_PENALTY, true,
+                        new LeafPosition(this, -1), false));
             }
         }
 
index 4680f642e5d0c1826affc23bce9da77c1883443d..d0dcc2bb821c51a2aaf00982a911d5372d6ce42b 100644 (file)
@@ -296,7 +296,8 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
         log.warn(this.getClass().getName() + " should not receive a call to removeWordSpace(list)");
     }
 
-    public void getWordChars(StringBuffer sbChars, Position pos) {
+    public String getWordChars(Position pos) {
+        return "";
     }
 
     public void hyphenate(Position pos, HyphContext hc) {
index 6e0c34a8266a6e2a45d19d338334c7c296b37e44..26f8e3b97573d7531a07e73d0c360d8eb70451ee 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr.inline;
 
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -144,7 +145,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
             padding += borderProps.getPadding(CommonBorderPaddingBackground.AFTER, false, this);
             padding += borderProps.getBorderWidth(CommonBorderPaddingBackground.AFTER, false);
         }
-        extraBPD = new MinOptMax(padding);
+        extraBPD = MinOptMax.getInstance(padding);
 
     }
 
@@ -161,7 +162,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
             borderAndPadding
                 += borderProps.getBorderWidth(CommonBorderPaddingBackground.END, isNotLast);
         }
-        return new MinOptMax(borderAndPadding);
+        return MinOptMax.getInstance(borderAndPadding);
     }
 
 
@@ -325,16 +326,20 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
                     KnuthSequence sequence = (KnuthSequence) seqIter.next();
                     sequence.wrapPositions(this);
                 }
+                int insertionStartIndex = 0;
                 if (lastSequence != null && lastSequence.appendSequenceOrClose
                         ((KnuthSequence) returnedList.get(0))) {
-                    returnedList.remove(0);
+                    insertionStartIndex = 1;
                 }
                 // add border and padding to the first complete sequence of this LM
                 if (!borderAdded && !returnedList.isEmpty()) {
                     addKnuthElementsForBorderPaddingStart((KnuthSequence) returnedList.get(0));
                     borderAdded = true;
                 }
-                returnList.addAll(returnedList);
+                for (Iterator iter = returnedList.listIterator(insertionStartIndex);
+                        iter.hasNext();) {
+                    returnList.add(iter.next());
+                }
             } else { // A block LM
                 BlockKnuthSequence sequence = new BlockKnuthSequence(returnedList);
                 sequence.wrapPositions(this);
@@ -488,8 +493,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
         boolean isLast = (getContext().isLastArea() && prevLM == lastChildLM);
 
         if (hasTrailingFence(isLast)) {
-            addSpace(getCurrentArea(),
-                     getContext().getTrailingSpace().resolve(false),
+            addSpace(getCurrentArea(), getContext().getTrailingSpace().resolve(false),
                      getContext().getSpaceAdjust());
             context.setTrailingSpace(new SpaceSpecifier(false));
         } else {
@@ -504,7 +508,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
         // Not sure if lastPos can legally be null or if that masks a different problem.
         // But it seems to fix bug 38053.
         setTraits(areaCreated, lastPos == null || !isLast(lastPos));
-        parentLM.addChildArea(getCurrentArea());
+        parentLayoutManager.addChildArea(getCurrentArea());
 
         addMarkersToPage(
                 false,
@@ -520,8 +524,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
     public void addChildArea(Area childArea) {
         Area parent = getCurrentArea();
         if (getContext().resolveLeadingSpace()) {
-            addSpace(parent,
-                    getContext().getLeadingSpace().resolve(false),
+            addSpace(parent, getContext().getLeadingSpace().resolve(false),
                     getContext().getSpaceAdjust());
         }
         parent.addChildArea(childArea);
index b080f926b0a3719912a974e1cfc02cba898aafe6..525f0407d3709d4f4db196332d4efe498b721c07 100644 (file)
@@ -48,20 +48,19 @@ public interface InlineLevelLayoutManager extends LayoutManager {
     void removeWordSpace(List oldList);
 
     /**
-     * Get the word chars corresponding to the given position
+     * 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
+     * @param pos     the position referring to the needed word chars.
      */
-    void getWordChars(StringBuffer sbChars, Position pos);
+    String getWordChars(Position pos);
 
     /**
      * Tell the LM to hyphenate a word
      *
      * @param pos the Position referring to the word
-     * @param hc  the HyphContext storing hyphenation information
+     * @param hyphContext  the HyphContext storing hyphenation information
      */
-    void hyphenate(Position pos, HyphContext hc);
+    void hyphenate(Position pos, HyphContext hyphContext);
 
     /**
      * Tell the LM to apply the changes due to hyphenation
index 65e59554fe72bcbb0906af12980e609175963616..375afb82fcff68a446911aa93ad4f64960ea90d2 100644 (file)
@@ -80,7 +80,7 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
      */
     protected InlineStackingLayoutManager(FObj node) {
         super(node);
-        extraBPD = new MinOptMax(0);
+        extraBPD = MinOptMax.ZERO;
     }
 
     /**
@@ -100,7 +100,7 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
      * @return the extra IPD as a MinOptMax spec
      */
     protected MinOptMax getExtraIPD(boolean bNotFirst, boolean bNotLast) {
-        return new MinOptMax(0);
+        return MinOptMax.ZERO;
     }
 
 
@@ -179,23 +179,21 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
     }
 
     /**
-     * Adds a space to the area
+     * Adds a space to the area.
+     *
      * @param parentArea the area to which to add the space
      * @param spaceRange the space range specifier
-     * @param dSpaceAdjust the factor by which to stretch or shrink the space
+     * @param spaceAdjust the factor by which to stretch or shrink the space
      */
-    protected void addSpace(Area parentArea, MinOptMax spaceRange,
-                            double dSpaceAdjust) {
+    protected void addSpace(Area parentArea, MinOptMax spaceRange, double spaceAdjust) {
         if (spaceRange != null) {
-            int iAdjust = spaceRange.opt;
-            if (dSpaceAdjust > 0.0) {
+            int iAdjust = spaceRange.getOpt();
+            if (spaceAdjust > 0.0) {
                 // Stretch by factor
-                iAdjust += (int) ((double) (spaceRange.max
-                                          - spaceRange.opt) * dSpaceAdjust);
-            } else if (dSpaceAdjust < 0.0) {
+                iAdjust += (int) (spaceRange.getStretch() * spaceAdjust);
+            } else if (spaceAdjust < 0.0) {
                 // Shrink by factor
-                iAdjust += (int) ((double) (spaceRange.opt
-                                          - spaceRange.min) * dSpaceAdjust);
+                iAdjust += (int) (spaceRange.getShrink() * spaceAdjust);
             }
             if (iAdjust != 0) {
                 //getLogger().debug("Add leading space: " + iAdjust);
@@ -257,10 +255,9 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
     }
 
     /** {@inheritDoc} */
-    public void getWordChars(StringBuffer sbChars, Position pos) {
+    public String getWordChars(Position pos) {
         Position newPos = pos.getPosition();
-        ((InlineLevelLayoutManager)
-         newPos.getLM()).getWordChars(sbChars, newPos);
+        return ((InlineLevelLayoutManager) newPos.getLM()).getWordChars(newPos);
     }
 
     /** {@inheritDoc} */
index 6c8c7354b17df91b4cafdf048225fd5171ce0244..7b08a67db83effac87d6a346144d88b08da4a09a 100644 (file)
@@ -19,7 +19,6 @@
 
 package org.apache.fop.layoutmgr.inline;
 
-import org.apache.fop.layoutmgr.inline.AlignmentContext;
 import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.Position;
@@ -32,13 +31,13 @@ public class KnuthInlineBox extends KnuthBox {
     /**
      * Create a new KnuthBox.
      *
-     * @param w    the width of this box
+     * @param width            the width of this box
      * @param alignmentContext the alignmentContext for this box
-     * @param pos  the Position stored in this box
-     * @param bAux is this box auxiliary?
+     * @param pos              the Position stored in this box
+     * @param auxiliary        is this box auxiliary?
      */
-    public KnuthInlineBox(int w, AlignmentContext alignmentContext, Position pos, boolean bAux) {
-        super(w, pos, bAux);
+    public KnuthInlineBox(int width, AlignmentContext alignmentContext, Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
         this.alignmentContext = alignmentContext;
     }
 
@@ -69,11 +68,4 @@ public class KnuthInlineBox extends KnuthBox {
     public boolean isAnchor() {
         return (footnoteBodyLM != null);
     }
-
-
-    /** {@inheritDoc} */
-    public String toString() {
-        StringBuffer sb = new StringBuffer(super.toString());
-        return sb.toString();
-    }
-}
\ No newline at end of file
+}
index fe82245b93eb8dabbbb59875414e999c93fbf5b3..c5f38134bb4f47c25bf42d01c9b1360574e26964 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr.inline;
 
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -109,7 +110,7 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
                     - borderPaddingWidth;
         int max = fobj.getLeaderLength().getMaximum(this).getLength().getValue(this)
                     - borderPaddingWidth;
-        return new MinOptMax(min, opt, max);
+        return MinOptMax.getInstance(min, opt, max);
     }
 
     private InlineArea getLeaderInlineArea(LayoutContext context) {
@@ -226,7 +227,7 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
             KnuthPossPosIter contentIter = new KnuthPossPosIter(contentList, 0, contentList.size());
             clm.addAreas(contentIter, context);
 
-            parentLM.addChildArea(curArea);
+            parentLayoutManager.addChildArea(curArea);
 
             while (posIter.hasNext()) {
                 posIter.next();
@@ -235,8 +236,7 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
     }
 
     /** {@inheritDoc} */
-    public List getNextKnuthElements(LayoutContext context,
-                                           int alignment) {
+    public List getNextKnuthElements(LayoutContext context, int alignment) {
         MinOptMax ipd;
         curArea = get(context);
         KnuthSequence seq = new InlineKnuthSequence();
@@ -256,45 +256,34 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
         ipd = getAllocationIPD(context.getRefIPD());
         if (fobj.getLeaderPattern() == EN_USECONTENT && curArea instanceof FilledArea) {
             // If we have user supplied content make it fit if we can
-            int unitWidth = ((FilledArea)curArea).getUnitWidth();
-            if (ipd.opt < unitWidth && ipd.max >= unitWidth) {
-                ipd.opt = unitWidth;
+            int unitWidth = ((FilledArea) curArea).getUnitWidth();
+            if (ipd.getOpt() < unitWidth && unitWidth <= ipd.getMax()) {
+                ipd = MinOptMax.getInstance(ipd.getMin(), unitWidth, ipd.getMax());
             }
         }
 
         // create the AreaInfo object to store the computed values
         areaInfo = new AreaInfo((short) 0, ipd, false, context.getAlignmentContext());
-        curArea.setAdjustingInfo(ipd.max - ipd.opt, ipd.opt - ipd.min, 0);
+        curArea.setAdjustingInfo(ipd.getStretch(), ipd.getShrink(), 0);
 
         addKnuthElementsForBorderPaddingStart(seq);
 
         // node is a fo:Leader
-        seq.add(new KnuthInlineBox(0, alignmentContext,
-                                    new LeafPosition(this, -1), true));
+        seq.add(new KnuthInlineBox(0, alignmentContext, new LeafPosition(this, -1), true));
         seq.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
-                                        new LeafPosition(this, -1), true));
+                new LeafPosition(this, -1), true));
         if (alignment == EN_JUSTIFY || alignment == 0) {
-            seq.add
-                (new KnuthGlue(areaInfo.ipdArea.opt,
-                               areaInfo.ipdArea.max - areaInfo.ipdArea.opt,
-                               areaInfo.ipdArea.opt - areaInfo.ipdArea.min,
-                               new LeafPosition(this, 0), false));
+            seq.add(new KnuthGlue(areaInfo.ipdArea, new LeafPosition(this, 0), false));
         } else {
-            seq.add
-                (new KnuthGlue(areaInfo.ipdArea.opt,
-                               0,
-                               0,
-                               new LeafPosition(this, 0), false));
+            seq.add(new KnuthGlue(areaInfo.ipdArea.getOpt(), 0, 0,
+                    new LeafPosition(this, 0), false));
         }
-        seq.add(new KnuthInlineBox(0, alignmentContext,
-                                    new LeafPosition(this, -1), true));
+        seq.add(new KnuthInlineBox(0, alignmentContext, new LeafPosition(this, -1), true));
 
         addKnuthElementsForBorderPaddingEnd(seq);
 
-        LinkedList returnList = new LinkedList();
-        returnList.add(seq);
         setFinished(true);
-        return returnList;
+        return Collections.singletonList(seq);
     }
 
     /** {@inheritDoc} */
@@ -310,8 +299,7 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
     }
 
     /** {@inheritDoc} */
-    public List getChangedKnuthElements(List oldList,
-                                              int alignment) {
+    public List getChangedKnuthElements(List oldList, int alignment) {
         if (isFinished()) {
             return null;
         }
@@ -325,17 +313,10 @@ public class LeaderLayoutManager extends LeafNodeLayoutManager {
         returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
                                         new LeafPosition(this, -1), true));
         if (alignment == EN_JUSTIFY || alignment == 0) {
-            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 KnuthGlue(areaInfo.ipdArea, new LeafPosition(this, 0), false));
         } else {
-            returnList.add
-                (new KnuthGlue(areaInfo.ipdArea.opt,
-                               0,
-                               0,
-                               new LeafPosition(this, 0), false));
+            returnList.add(new KnuthGlue(areaInfo.ipdArea.getOpt(), 0, 0,
+                    new LeafPosition(this, 0), false));
         }
         returnList.add(new KnuthInlineBox(0, areaInfo.alignmentContext,
                                     new LeafPosition(this, -1), true));
index ac501abb75b96ac38a9ffd1765aa25f9a818e0ae..e74b51d96468ef62982c3318b4639a52d7738849 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.inline;
 
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Collections;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -163,7 +164,7 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
      * @return the min/opt/max ipd of the inline area
      */
     protected MinOptMax getAllocationIPD(int refIPD) {
-        return new MinOptMax(curArea.getIPD());
+        return MinOptMax.getInstance(curArea.getIPD());
     }
 
     /**
@@ -186,7 +187,7 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
                                                    false, false, this);
                 TraitSetter.addBackground(area, commonBorderPaddingBackground, this);
             }
-            parentLM.addChildArea(area);
+            parentLayoutManager.addChildArea(area);
         }
 
         while (posIter.hasNext()) {
@@ -236,16 +237,14 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
      */
     protected void widthAdjustArea(InlineArea area, LayoutContext context) {
         double dAdjust = context.getIPDAdjust();
-        int width = areaInfo.ipdArea.opt;
+        int adjustment = 0;
         if (dAdjust < 0) {
-            width = (int) (width + dAdjust * (areaInfo.ipdArea.opt
-                                             - areaInfo.ipdArea.min));
+            adjustment += (int) (dAdjust * areaInfo.ipdArea.getShrink());
         } else if (dAdjust > 0) {
-            width = (int) (width + dAdjust * (areaInfo.ipdArea.max
-                                             - areaInfo.ipdArea.opt));
+            adjustment += (int) (dAdjust * areaInfo.ipdArea.getStretch());
         }
-        area.setIPD(width);
-        area.setAdjustment(width - areaInfo.ipdArea.opt);
+        area.setIPD(areaInfo.ipdArea.getOpt() + adjustment);
+        area.setAdjustment(adjustment);
     }
 
     /** {@inheritDoc} */
@@ -270,16 +269,13 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
 
         addKnuthElementsForBorderPaddingStart(seq);
 
-        seq.add(new KnuthInlineBox(areaInfo.ipdArea.opt, alignmentContext,
+        seq.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), alignmentContext,
                                     notifyPos(new LeafPosition(this, 0)), false));
 
         addKnuthElementsForBorderPaddingEnd(seq);
 
-        LinkedList returnList = new LinkedList();
-
-        returnList.add(seq);
         setFinished(true);
-        return returnList;
+        return Collections.singletonList(seq);
     }
 
     /** {@inheritDoc} */
@@ -299,11 +295,12 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
     }
 
     /** {@inheritDoc} */
-    public void getWordChars(StringBuffer sbChars, Position pos) {
+    public String getWordChars(Position pos) {
+        return "";
     }
 
     /** {@inheritDoc} */
-    public void hyphenate(Position pos, HyphContext hc) {
+    public void hyphenate(Position pos, HyphContext hyphContext) {
     }
 
     /** {@inheritDoc} */
@@ -325,7 +322,7 @@ public abstract class LeafNodeLayoutManager extends AbstractLayoutManager
 
         // fobj is a fo:ExternalGraphic, fo:InstreamForeignObject,
         // fo:PageNumber or fo:PageNumberCitation
-        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.opt, areaInfo.alignmentContext,
+        returnList.add(new KnuthInlineBox(areaInfo.ipdArea.getOpt(), areaInfo.alignmentContext,
                                           notifyPos(new LeafPosition(this, 0)), true));
 
         addKnuthElementsForBorderPaddingEnd(returnList);
index 0b95ef859d72f5f57e6adc9d135aecfb53adbb2a..0ece70cac817b8ba392f4d48193f7d1a99ca4766 100644 (file)
@@ -43,6 +43,7 @@ import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.fonts.FontTriplet;
 import org.apache.fop.hyphenation.Hyphenation;
 import org.apache.fop.hyphenation.Hyphenator;
+import org.apache.fop.layoutmgr.Adjustment;
 import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.BreakingAlgorithm;
@@ -235,11 +236,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             // set the minimum amount of empty space at the end of the
             // last line
             if (textAlignment == EN_CENTER) {
-                lineFiller = new MinOptMax(lastLineEndIndent);
+                lineFiller = MinOptMax.getInstance(lastLineEndIndent);
             } else {
-                lineFiller = new MinOptMax(lastLineEndIndent,
-                                            lastLineEndIndent,
-                                            layoutManager.ipd);
+                lineFiller = MinOptMax.getInstance(lastLineEndIndent, lastLineEndIndent,
+                        layoutManager.ipd);
             }
 
             // add auxiliary elements at the beginning of the paragraph
@@ -272,7 +272,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                     && textAlignmentLast != EN_JUSTIFY) {
                     this.add(new KnuthGlue(0, 3 * DEFAULT_SPACE_WIDTH, 0,
                                            null, false));
-                    this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
+                    this.add(new KnuthPenalty(lineFiller.getOpt(), -KnuthElement.INFINITE,
                                               false, null, false));
                     ignoreAtEnd = 2;
                 } else if (textAlignmentLast != EN_JUSTIFY) {
@@ -282,14 +282,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                     this.add(new KnuthPenalty(0, KnuthElement.INFINITE,
                                               false, null, false));
                     this.add(new KnuthGlue(0,
-                            lineFiller.max - lineFiller.opt,
-                            lineFiller.opt - lineFiller.min, null, false));
-                    this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
+                            lineFiller.getStretch(),
+                            lineFiller.getShrink(), null, false));
+                    this.add(new KnuthPenalty(lineFiller.getOpt(), -KnuthElement.INFINITE,
                                               false, null, false));
                     ignoreAtEnd = 3;
                 } else {
                     // add only the element representing the forced break
-                    this.add(new KnuthPenalty(lineFiller.opt, -KnuthElement.INFINITE,
+                    this.add(new KnuthPenalty(lineFiller.getOpt(), -KnuthElement.INFINITE,
                                               false, null, false));
                     ignoreAtEnd = 1;
                 }
@@ -393,7 +393,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                    (bestActiveNode.line > 1 ? bestActiveNode.previous.position + 1 : 0),
                    bestActiveNode.position,
                    bestActiveNode.availableShrink - (addedPositions > 0
-                       ? 0 : ((Paragraph)par).lineFiller.opt - ((Paragraph)par).lineFiller.min),
+                       ? 0 : ((Paragraph) par).lineFiller.getShrink()),
                    bestActiveNode.availableStretch,
                    difference, ratio, indent), activePossibility);
             addedPositions++;
@@ -784,7 +784,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         int iBPcount = 0;
         LineBreakingAlgorithm alg = new LineBreakingAlgorithm(alignment,
                                         textAlignment, textAlignmentLast,
-                                        textIndent.getValue(this), currPar.lineFiller.opt,
+                                        textIndent.getValue(this), currPar.lineFiller.getOpt(),
                                         lineHeight.getValue(this), lead, follow,
                                         (knuthParagraphs.indexOf(currPar) == 0),
                                         hyphenationLadderCount.getEnum() == EN_NO_LIMIT
@@ -1057,12 +1057,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             breaker.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
             breaker.add(new KnuthGlue(0, -nConditionalOptionalLines * constantLineHeight,
                                         -nConditionalEliminableLines * constantLineHeight,
-                                        LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+                                        Adjustment.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));
+                                        Adjustment.LINE_NUMBER_ADJUSTMENT, elementPosition, false));
         } else if (nLastLines != 0) {
             breaker.add(new KnuthPenalty(0, 0, false, elementPosition, false));
         }
@@ -1083,7 +1083,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             list.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, elementPosition, false));
             list.add(new KnuthGlue(0, nConditionalOptionalLines * constantLineHeight,
                                    nConditionalEliminableLines * constantLineHeight,
-                                   LINE_NUMBER_ADJUSTMENT, elementPosition, false));
+                                   Adjustment.LINE_NUMBER_ADJUSTMENT, elementPosition, false));
             list.add(new KnuthBox(0, elementPosition,
                                   (nLastLines == 0 ? true : false)));
         }
@@ -1094,7 +1094,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             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));
+                                   Adjustment.LINE_NUMBER_ADJUSTMENT, elementPosition, false));
             list.add(new KnuthBox(0, elementPosition, false));
         }
 
@@ -1104,7 +1104,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             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));
+                                   Adjustment.LINE_NUMBER_ADJUSTMENT, elementPosition, false));
             list.add(new KnuthBox(0, elementPosition, false));
         }
 
@@ -1200,7 +1200,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             llPoss = (LineLayoutPossibilities)lineLayoutsList.get(p);
             //log.debug("demerits of the chosen layout: " + llPoss.getChosenDemerits());
             for (int i = 0; i < llPoss.getChosenLineCount(); i++) {
-                if (!((BlockLevelLayoutManager) parentLM).mustKeepTogether()
+                if (!((BlockLevelLayoutManager) parentLayoutManager).mustKeepTogether()
                     && i >= fobj.getOrphans()
                     && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
                     // null penalty allowing a page break between lines
@@ -1213,21 +1213,19 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 //log.debug("linewidth= " + lbp.lineWidth + " difference= " + lbp.difference + " indent= " + lbp.startIndent);
                 MinOptMax contentIPD;
                 if (alignment == EN_JUSTIFY) {
-                    contentIPD = new MinOptMax(
+                    contentIPD = MinOptMax.getInstance(
                         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);
+                    contentIPD = MinOptMax.getInstance(lbp.lineWidth - 2 * lbp.startIndent);
                 } else if (alignment == EN_END) {
-                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.startIndent);
+                    contentIPD = MinOptMax.getInstance(lbp.lineWidth - lbp.startIndent);
                 } else {
-                    contentIPD = new MinOptMax(lbp.lineWidth - lbp.difference + lbp.startIndent);
+                    contentIPD = MinOptMax.getInstance(lbp.lineWidth - lbp.difference + lbp.startIndent);
                 }
-                returnList.add(new KnuthBlockBox(lbp.lineHeight,
-                                                 contentIPD,
-                                                 (lbp.ipdAdjust != 0
-                                                         ? lbp.lineWidth - lbp.difference : 0),
+                returnList.add(new KnuthBlockBox(lbp.lineHeight, contentIPD, (lbp.ipdAdjust != 0
+                        ? lbp.lineWidth - lbp.difference : 0),
                                                  lbp, false));
             }
         }
@@ -1277,7 +1275,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                 boxCount = 1;
                 auxCount = 0;
                 sbChars = new StringBuffer();
-                currLM.getWordChars(sbChars, firstElement.getPosition());
+                sbChars.append(currLM.getWordChars(firstElement.getPosition()));
                 // look if next elements are boxes too
                 while (currParIterator.hasNext()) {
                     nextElement = (KnuthElement) currParIterator.next();
@@ -1289,7 +1287,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
                         }
                         // append text to recreate the whole word
                         boxCount++;
-                        currLM.getWordChars(sbChars, nextElement.getPosition());
+                        sbChars.append(currLM.getWordChars(nextElement.getPosition()));
                     } else if (!nextElement.isAuxiliary()) {
                         // a non-auxiliary non-box KnuthElement: stop
                         // go back to the last box or auxiliary element
@@ -1583,7 +1581,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
         }
         lineArea.finalise();
-        parentLM.addChildArea(lineArea);
+        parentLayoutManager.addChildArea(lineArea);
     }
 
     /**
@@ -1633,7 +1631,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
             blocklc.setTrailingSpace(new SpaceSpecifier(false));
         }
         lineArea.updateExtentsFromChildren();
-        parentLM.addChildArea(lineArea);
+        parentLayoutManager.addChildArea(lineArea);
     }
 
     /**
@@ -1644,9 +1642,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
         if (childArea instanceof InlineArea) {
             Area parent = getCurrentArea();
             if (getContext().resolveLeadingSpace()) {
-                addSpace(parent,
-                         getContext().getLeadingSpace().resolve(false),
-                         getContext().getSpaceAdjust());
+                addSpace(parent, getContext().getLeadingSpace().resolve(false),
+                        getContext().getSpaceAdjust());
             }
             parent.addChildArea(childArea);
         }
index d33f2cca1c065f59dda6256765ecc385f31d9228..a38e3e2d84c12984b3e2e0117207d712a2a93311 100644 (file)
@@ -46,7 +46,7 @@ public class PageNumberCitationLastLayoutManager extends AbstractPageNumberCitat
 
     /** {@inheritDoc} */
     public InlineArea get(LayoutContext context) {
-        curArea = getPageNumberCitationLastInlineArea(parentLM);
+        curArea = getPageNumberCitationLastInlineArea(parentLayoutManager);
         return curArea;
     }
 
index 5cae072075eab9e0bfaa081b6b439d4debd88999..d8cfe6cda229cc0e000f95e91f64e7c2067fc08d 100644 (file)
@@ -116,7 +116,7 @@ public class PageNumberLayoutManager extends LeafNodeLayoutManager {
         // update the ipd of the area
         area.handleIPDVariation(getStringWidth(area.getText()) - area.getIPD());
         // update the width stored in the AreaInfo object
-        areaInfo.ipdArea = new MinOptMax(area.getIPD());
+        areaInfo.ipdArea = MinOptMax.getInstance(area.getIPD());
     }
 
     /**
index f793bb3bb0ab4255936b5d39db44584aec5ffd16..43e8c5a31641bc328fbc15de83c832b5475f84d1 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr.inline;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
@@ -59,6 +60,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
 
     //TODO: remove all final modifiers at local variables
 
+    // static final int SOFT_HYPHEN_PENALTY = KnuthPenalty.FLAGGED_PENALTY / 10;
+    private static final int SOFT_HYPHEN_PENALTY = 1;
+
     /**
      * Store information about each potential text area.
      * Index of character which ends the area, IPD of area, including
@@ -66,25 +70,27 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      * Number of word-spaces?
      */
     private class AreaInfo {
+
         private final int startIndex;
         private final int breakIndex;
         private final int wordSpaceCount;
         private int letterSpaceCount;
-        private final MinOptMax areaIPD;
+        private MinOptMax areaIPD;
         private final boolean isHyphenated;
         private final boolean isSpace;
         private boolean breakOppAfter;
         private final Font font;
 
         AreaInfo(final int startIndex,
-                        final int breakIndex,
-                        final int wordSpaceCount,
-                        final int letterSpaceCount,
-                        final MinOptMax areaIPD,
-                        final boolean isHyphenated,
-                        final boolean isSpace,
-                        final boolean breakOppAfter,
-                        final Font font) {
+                 final int breakIndex,
+                 final int wordSpaceCount,
+                 final int letterSpaceCount,
+                 final MinOptMax areaIPD,
+                 final boolean isHyphenated,
+                 final boolean isSpace,
+                 final boolean breakOppAfter,
+                 final Font font) {
+            assert startIndex <= breakIndex;
             this.startIndex = startIndex;
             this.breakIndex = breakIndex;
             this.wordSpaceCount = wordSpaceCount;
@@ -96,28 +102,38 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             this.font = font;
         }
 
-        public String toString() {
-            return "[ lscnt=" + this.letterSpaceCount
-                + ", wscnt=" + this.wordSpaceCount
-                + ", ipd=" + this.areaIPD.toString()
-                + ", sidx=" + this.startIndex
-                + ", bidx=" + this.breakIndex
-                + ", hyph=" + this.isHyphenated
-                + ", space=" + this.isSpace
-                + ", font=" + this.font
-                + "]";
+        private int getCharLength() {
+            return breakIndex - startIndex;
+        }
+
+        private void addToAreaIPD(MinOptMax idp) {
+            areaIPD = areaIPD.plus(idp);
         }
 
+        public String toString() {
+            return "AreaInfo["
+                    + "letterSpaceCount = " + letterSpaceCount
+                    + ", wordSpaceCount = " + wordSpaceCount
+                    + ", areaIPD = " + areaIPD
+                    + ", startIndex = " + startIndex
+                    + ", breakIndex = " + breakIndex
+                    + ", isHyphenated = " + isHyphenated
+                    + ", isSpace = " + isSpace
+                    + ", font = " + font
+                    + "]";
+        }
     }
 
-    // this class stores information about changes in vecAreaInfo
-    // which are not yet applied
+    /**
+     * this class stores information about changes in vecAreaInfo which are not yet applied
+     */
     private final class PendingChange {
-        private final AreaInfo ai;
+
+        private final AreaInfo areaInfo;
         private final int index;
 
-        private PendingChange(final AreaInfo ai, final int index) {
-            this.ai = ai;
+        private PendingChange(final AreaInfo areaInfo, final int index) {
+            this.areaInfo = areaInfo;
             this.index = index;
         }
     }
@@ -128,14 +144,11 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     private static final Log LOG = LogFactory.getLog(TextLayoutManager.class);
 
     // Hold all possible breaks for the text in this LM's FO.
-    private final List vecAreaInfo;
+    private final List areaInfos;
 
     /** Non-space characters on which we can end a line. */
     private static final String BREAK_CHARS = "-/";
 
-    /** Used to reduce instantiation of MinOptMax with zero length. Do not modify! */
-    private static final MinOptMax ZERO_MINOPTMAX = new MinOptMax(0);
-
     private final FOText foText;
 
     /**
@@ -155,18 +168,23 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     private MinOptMax letterSpaceIPD;
     /** size of the hyphen character glyph in current font */
     private int hyphIPD;
-    /** 1/1 of word-spacing value */
-    private SpaceVal ws;
 
     private boolean hasChanged = false;
     private int returnedIndex = 0;
     private int thisStart = 0;
     private int tempStart = 0;
-    private List changeList = null;
+    private List changeList = new LinkedList();
 
     private AlignmentContext alignmentContext = null;
 
+    /**
+     * The width to be reserved for border and padding at the start of the line.
+     */
     private int lineStartBAP = 0;
+
+    /**
+     * The width to be reserved for border and padding at the end of the line.
+     */
     private int lineEndBAP = 0;
 
     private boolean keepTogether;
@@ -178,49 +196,37 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      *
      * @param node The FOText object to be rendered
      */
-    public TextLayoutManager(final FOText node) {
-        super();
-        this.foText = node;
-
-        this.letterAdjustArray = new MinOptMax[node.length() + 1];
-
-        this.vecAreaInfo = new java.util.ArrayList();
+    public TextLayoutManager(FOText node) {
+        foText = node;
+        letterAdjustArray = new MinOptMax[node.length() + 1];
+        areaInfos = new ArrayList();
     }
 
-    private KnuthPenalty makeZeroWidthPenalty(final int penaltyValue) {
-        return new KnuthPenalty(
-                0,
-                penaltyValue,
-                false,
-                this.auxiliaryPosition,
-                true);
+    private KnuthPenalty makeZeroWidthPenalty(int penaltyValue) {
+        return new KnuthPenalty(0, penaltyValue, false, auxiliaryPosition, true);
     }
 
     private KnuthBox makeAuxiliaryZeroWidthBox() {
-        return new KnuthInlineBox(
-                0,
-                null,
-                this.notifyPos(new LeafPosition(this, -1)),
-                true);
+        return new KnuthInlineBox(0, null, notifyPos(new LeafPosition(this, -1)), true);
     }
 
     /** {@inheritDoc} */
     public void initialize() {
 
-        this.foText.resetBuffer();
+        foText.resetBuffer();
 
-        this.spaceFont = FontSelector.selectFontForCharacterInText(' ', this.foText, this);
+        spaceFont = FontSelector.selectFontForCharacterInText(' ', foText, this);
 
-        // With CID fonts, space isn't neccesary currentFontState.width(32)
-        this.spaceCharIPD = this.spaceFont.getCharWidth(' ');
-        // Use hyphenationChar property
+        // With CID fonts, space isn't necessary currentFontState.width(32)
+        spaceCharIPD = spaceFont.getCharWidth(' ');
 
+        // Use hyphenationChar property
         // TODO: Use hyphen based on actual font used!
-        this.hyphIPD = this.foText.getCommonHyphenation().getHyphIPD(this.spaceFont);
+        hyphIPD = foText.getCommonHyphenation().getHyphIPD(spaceFont);
 
-        final SpaceVal ls = SpaceVal.makeLetterSpacing(this.foText.getLetterSpacing());
-
-        this.ws = SpaceVal.makeWordSpacing(this.foText.getWordSpacing(), ls, this.spaceFont);
+        SpaceVal letterSpacing = SpaceVal.makeLetterSpacing(foText.getLetterSpacing());
+        SpaceVal wordSpacing = SpaceVal.makeWordSpacing(foText.getWordSpacing(), letterSpacing,
+                spaceFont);
 
         // letter space applies only to consecutive non-space characters,
         // while word space applies to space characters;
@@ -233,12 +239,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         // set letter space and word space dimension;
         // the default value "normal" was converted into a MinOptMax value
         // in the SpaceVal.makeWordSpacing() method
-        this.letterSpaceIPD = ls.getSpace();
-        this.wordSpaceIPD = MinOptMax.add(new MinOptMax(this.spaceCharIPD), this.ws.getSpace());
-
-        this.keepTogether = this.foText.getKeepTogether().getWithinLine()
-                .getEnum() == Constants.EN_ALWAYS;
-
+        letterSpaceIPD = letterSpacing.getSpace();
+        wordSpaceIPD = MinOptMax.getInstance(spaceCharIPD).plus(wordSpacing.getSpace());
+        keepTogether = foText.getKeepTogether().getWithinLine().getEnum() == Constants.EN_ALWAYS;
     }
 
     /**
@@ -254,111 +257,103 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
     public void addAreas(final PositionIterator posIter, final LayoutContext context) {
 
         // Add word areas
-        AreaInfo ai;
+        AreaInfo areaInfo;
         int wordSpaceCount = 0;
         int letterSpaceCount = 0;
         int firstAreaInfoIndex = -1;
         int lastAreaInfoIndex = 0;
-        MinOptMax realWidth = new MinOptMax(0);
+        MinOptMax realWidth = MinOptMax.ZERO;
 
         /* On first area created, add any leading space.
          * Calculate word-space stretch value.
          */
-        AreaInfo lastAi = null;
+        AreaInfo lastAreaInfo = null;
         while (posIter.hasNext()) {
             final LeafPosition tbpNext = (LeafPosition) posIter.next();
             if (tbpNext == null) {
                 continue; //Ignore elements without Positions
             }
             if (tbpNext.getLeafPos() != -1) {
-                ai = (AreaInfo) this.vecAreaInfo.get(tbpNext.getLeafPos());
-                if (lastAi == null || ai.font != lastAi.font) {
-                    if (lastAi != null) {
-                        this.addAreaInfoAreas(lastAi, wordSpaceCount,
+                areaInfo = (AreaInfo) areaInfos.get(tbpNext.getLeafPos());
+                if (lastAreaInfo == null || areaInfo.font != lastAreaInfo.font) {
+                    if (lastAreaInfo != null) {
+                        addAreaInfoAreas(lastAreaInfo, wordSpaceCount,
                                 letterSpaceCount, firstAreaInfoIndex,
                                 lastAreaInfoIndex, realWidth, context);
                     }
                     firstAreaInfoIndex = tbpNext.getLeafPos();
                     wordSpaceCount = 0;
                     letterSpaceCount = 0;
-                    realWidth = new MinOptMax(0);
+                    realWidth = MinOptMax.ZERO;
                 }
-                wordSpaceCount += ai.wordSpaceCount;
-                letterSpaceCount += ai.letterSpaceCount;
-                realWidth.add(ai.areaIPD);
+                wordSpaceCount += areaInfo.wordSpaceCount;
+                letterSpaceCount += areaInfo.letterSpaceCount;
+                realWidth = realWidth.plus(areaInfo.areaIPD);
                 lastAreaInfoIndex = tbpNext.getLeafPos();
-                lastAi = ai;
+                lastAreaInfo = areaInfo;
             }
         }
-        if (lastAi != null) {
-            this.addAreaInfoAreas(lastAi, wordSpaceCount, letterSpaceCount,
-                    firstAreaInfoIndex, lastAreaInfoIndex, realWidth, context);
+        if (lastAreaInfo != null) {
+            addAreaInfoAreas(lastAreaInfo, wordSpaceCount, letterSpaceCount, firstAreaInfoIndex,
+                    lastAreaInfoIndex, realWidth, context);
         }
     }
 
-    private void addAreaInfoAreas(final AreaInfo ai, final int wordSpaceCount,
-            int letterSpaceCount, final int firstAreaInfoIndex,
-            final int lastAreaInfoIndex, final MinOptMax realWidth, final LayoutContext context) {
+    private void addAreaInfoAreas(AreaInfo areaInfo, int wordSpaceCount, int letterSpaceCount,
+                                  int firstAreaInfoIndex, int lastAreaInfoIndex,
+                                  MinOptMax realWidth, LayoutContext context) {
 
         // TODO: These two statements (if, for) were like this before my recent
         // changes. However, it seems as if they should use the AreaInfo from
-        // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last ai.
+        // firstAreaInfoIndex.. lastAreaInfoIndex rather than just the last areaInfo.
         // This needs to be checked.
-        final int textLength = ai.breakIndex - ai.startIndex;
-        if (ai.letterSpaceCount == textLength && !ai.isHyphenated
-                   && context.isLastArea()) {
+        int textLength = areaInfo.getCharLength();
+        if (areaInfo.letterSpaceCount == textLength && !areaInfo.isHyphenated
+                && context.isLastArea()) {
             // the line ends at a character like "/" or "-";
             // remove the letter space after the last character
-            realWidth.add(MinOptMax.multiply(this.letterSpaceIPD, -1));
+            realWidth = realWidth.minus(letterSpaceIPD);
             letterSpaceCount--;
         }
 
-        for (int i = ai.startIndex; i < ai.breakIndex; i++) {
-            final MinOptMax ladj = this.letterAdjustArray[i + 1];
-            if (ladj != null && ladj.isElastic()) {
+        for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+            MinOptMax letterAdjustment = letterAdjustArray[i + 1];
+            if (letterAdjustment != null && letterAdjustment.isElastic()) {
                 letterSpaceCount++;
             }
         }
 
         // add hyphenation character if the last word is hyphenated
-        if (context.isLastArea() && ai.isHyphenated) {
-            realWidth.add(new MinOptMax(this.hyphIPD));
+        if (context.isLastArea() && areaInfo.isHyphenated) {
+            realWidth = realWidth.plus(hyphIPD);
         }
 
-        // Calculate adjustments
-        int difference = 0;
-        int totalAdjust = 0;
-        int wordSpaceDim = this.wordSpaceIPD.opt;
-        int letterSpaceDim = this.letterSpaceIPD.opt;
-        final double ipdAdjust = context.getIPDAdjust();
+        /* Calculate adjustments */
+        double ipdAdjust = context.getIPDAdjust();
 
         // calculate total difference between real and available width
+        int difference;
         if (ipdAdjust > 0.0) {
-            difference = (int) ((realWidth.max - realWidth.opt)
-                                * ipdAdjust);
+            difference = (int) (realWidth.getStretch() * ipdAdjust);
         } else {
-            difference = (int) ((realWidth.opt - realWidth.min)
-                                * ipdAdjust);
+            difference = (int) (realWidth.getShrink() * ipdAdjust);
         }
 
         // set letter space adjustment
+        int letterSpaceDim = letterSpaceIPD.getOpt();
         if (ipdAdjust > 0.0) {
-            letterSpaceDim
-                += (int) ((this.letterSpaceIPD.max - this.letterSpaceIPD.opt)
-                         * ipdAdjust);
-        } else  {
-            letterSpaceDim
-                += (int) ((this.letterSpaceIPD.opt - this.letterSpaceIPD.min)
-                         * ipdAdjust);
+            letterSpaceDim += (int) (letterSpaceIPD.getStretch() * ipdAdjust);
+        } else {
+            letterSpaceDim += (int) (letterSpaceIPD.getShrink() * ipdAdjust);
         }
-        totalAdjust += (letterSpaceDim - this.letterSpaceIPD.opt) * letterSpaceCount;
+        int totalAdjust = (letterSpaceDim - letterSpaceIPD.getOpt()) * letterSpaceCount;
 
         // set word space adjustment
-        //
+        int wordSpaceDim = wordSpaceIPD.getOpt();
         if (wordSpaceCount > 0) {
             wordSpaceDim += (difference - totalAdjust) / wordSpaceCount;
         }
-        totalAdjust += (wordSpaceDim - this.wordSpaceIPD.opt) * wordSpaceCount;
+        totalAdjust += (wordSpaceDim - wordSpaceIPD.getOpt()) * wordSpaceCount;
         if (totalAdjust != difference) {
             // the applied adjustment is greater or smaller than the needed one
             TextLayoutManager.LOG
@@ -370,9 +365,8 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             totalAdjust = difference;
         }
 
-        final TextArea t = this.createTextArea(realWidth, totalAdjust, context,
-                this.wordSpaceIPD.opt - this.spaceCharIPD, firstAreaInfoIndex,
-                lastAreaInfoIndex, context.isLastArea(), ai.font);
+        TextArea textArea = new TextAreaBuilder(realWidth, totalAdjust, context, firstAreaInfoIndex,
+                lastAreaInfoIndex, context.isLastArea(), areaInfo.font).build();
 
         // wordSpaceDim is computed in relation to wordSpaceIPD.opt
         // but the renderer needs to know the adjustment in relation
@@ -386,133 +380,205 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         //     = spaceCharIPD + letterSpaceAdjust +
         //       + (wordSpaceDim - spaceCharIPD -  2 * letterSpaceAdjust)
         //     = wordSpaceDim - letterSpaceAdjust
-        t.setTextLetterSpaceAdjust(letterSpaceDim);
-        t.setTextWordSpaceAdjust(wordSpaceDim - this.spaceCharIPD
-                                 - 2 * t.getTextLetterSpaceAdjust());
+        textArea.setTextLetterSpaceAdjust(letterSpaceDim);
+        textArea.setTextWordSpaceAdjust(wordSpaceDim - spaceCharIPD
+                - 2 * textArea.getTextLetterSpaceAdjust());
         if (context.getIPDAdjust() != 0) {
             // add information about space width
-            t.setSpaceDifference(this.wordSpaceIPD.opt - this.spaceCharIPD
-                                 - 2 * t.getTextLetterSpaceAdjust());
+            textArea.setSpaceDifference(wordSpaceIPD.getOpt() - spaceCharIPD
+                    - 2 * textArea.getTextLetterSpaceAdjust());
         }
-        this.parentLM.addChildArea(t);
+        parentLayoutManager.addChildArea(textArea);
     }
 
-    /**
-     * Create an inline word area.
-     * This creates a TextArea and sets up the various attributes.
-     *
-     * @param width the MinOptMax width of the content
-     * @param adjust the total ipd adjustment with respect to the optimal width
-     * @param context the layout context
-     * @param spaceDiff unused
-     * @param firstIndex the index of the first AreaInfo used for the TextArea
-     * @param lastIndex the index of the last AreaInfo used for the TextArea
-     * @param isLastArea is this TextArea the last in a line?
-     * @param font Font to be used in this particular TextArea
-     * @return the new text area
-     */
-    protected TextArea createTextArea(final MinOptMax width, final int adjust,
-            final LayoutContext context, final int spaceDiff, final int firstIndex,
-            final int lastIndex, final boolean isLastArea, final Font font) {
-        TextArea textArea;
-        if (context.getIPDAdjust() == 0.0) {
-            // create just a TextArea
-            textArea = new TextArea();
-        } else {
-            // justified area: create a TextArea with extra info
-            // about potential adjustments
-            textArea = new TextArea(width.max - width.opt,
-                                    width.opt - width.min,
-                                    adjust);
+    private final class TextAreaBuilder {
+
+        private final MinOptMax width;
+        private final int adjust;
+        private final LayoutContext context;
+        private final int firstIndex;
+        private final int lastIndex;
+        private final boolean isLastArea;
+        private final Font font;
+
+        private int blockProgressionDimension;
+        private AreaInfo areaInfo;
+        private StringBuffer wordChars;
+        private int[] letterAdjust;
+        private int letterAdjustIndex;
+
+        private TextArea textArea;
+
+        /**
+         * Creates a new <code>TextAreaBuilder</code> which itself builds an inline word area. This
+         * creates a TextArea and sets up the various attributes.
+         *
+         * @param width      the MinOptMax width of the content
+         * @param adjust     the total ipd adjustment with respect to the optimal width
+         * @param context    the layout context
+         * @param firstIndex the index of the first AreaInfo used for the TextArea
+         * @param lastIndex  the index of the last AreaInfo used for the TextArea
+         * @param isLastArea is this TextArea the last in a line?
+         * @param font       Font to be used in this particular TextArea
+         */
+        private TextAreaBuilder(MinOptMax width, int adjust, LayoutContext context,
+                                int firstIndex, int lastIndex, boolean isLastArea, Font font) {
+            this.width = width;
+            this.adjust = adjust;
+            this.context = context;
+            this.firstIndex = firstIndex;
+            this.lastIndex = lastIndex;
+            this.isLastArea = isLastArea;
+            this.font = font;
         }
-        textArea.setIPD(width.opt + adjust);
-        textArea.setBPD(font.getAscender() - font.getDescender());
 
-        textArea.setBaselineOffset(font.getAscender());
-        if (textArea.getBPD() == this.alignmentContext.getHeight()) {
-            textArea.setOffset(0);
-        } else {
-            textArea.setOffset(this.alignmentContext.getOffset());
+        private TextArea build() {
+            createTextArea();
+            setInlineProgressionDimension();
+            calcBlockProgressionDimension();
+            setBlockProgressionDimension();
+            setBaselineOffset();
+            setOffset();
+            setText();
+            TraitSetter.addFontTraits(textArea, font);
+            textArea.addTrait(Trait.COLOR, foText.getColor());
+            TraitSetter.addPtr(textArea, getPtr()); // used for accessibility
+            TraitSetter.addTextDecoration(textArea, foText.getTextDecoration());
+            TraitSetter.addFontTraits(textArea, font);
+            return textArea;
         }
 
-        // set the text of the TextArea, split into words and spaces
-        int wordStartIndex = -1;
-        AreaInfo areaInfo;
-        int len = 0;
-        for (int i = firstIndex; i <= lastIndex; i++) {
-            areaInfo = (AreaInfo) this.vecAreaInfo.get(i);
-            if (areaInfo.isSpace) {
-                // areaInfo stores information about spaces
-                // add the spaces - except zero-width spaces - to the TextArea
-                for (int j = areaInfo.startIndex; j < areaInfo.breakIndex; j++) {
-                    final char spaceChar = this.foText.charAt(j);
-                    if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
-                        textArea.addSpace(spaceChar, 0,
-                                CharUtilities.isAdjustableSpace(spaceChar));
-                    }
-                }
+        /**
+         * Creates an plain <code>TextArea</code> or a justified <code>TextArea</code> with
+         * additional information.
+         */
+        private void createTextArea() {
+            if (context.getIPDAdjust() == 0.0) {
+                textArea = new TextArea();
             } else {
-                // areaInfo stores information about a word fragment
-                if (wordStartIndex == -1) {
-                    // here starts a new word
-                    wordStartIndex = i;
-                    len = 0;
-                }
-                len += areaInfo.breakIndex - areaInfo.startIndex;
-                if (i == lastIndex || ((AreaInfo) this.vecAreaInfo.get(i + 1)).isSpace) {
-                    // here ends a new word
-                    // add a word to the TextArea
-                    if (isLastArea
-                        && i == lastIndex
-                        && areaInfo.isHyphenated) {
-                        len++;
-                    }
-                    final StringBuffer wordChars = new StringBuffer(len);
-                    final int[] letterAdjust = new int[len];
-                    int letter = 0;
-                    for (int j = wordStartIndex; j <= i; j++) {
-                        final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(j);
-                        int lsCount = ai.letterSpaceCount;
-                        /* TODO: in Java 5, StringBuffer has an append() variant
-                         * for CharSequence, so the below iteration can be replaced
-                         * by:
-                         *  wordChars.append(this.foText, ai.startIndex,
-                         *       ai.breakIndex - ai.startIndex);
-                         */
-                        for (int ci = ai.startIndex; ci < ai.breakIndex; ci++) {
-                            wordChars.append(this.foText.charAt(ci));
-                        }
-                        for (int k = 0; k < ai.breakIndex - ai.startIndex; k++) {
-                            final MinOptMax adj = this.letterAdjustArray[ai.startIndex + k];
-                            if (letter > 0) {
-                                letterAdjust[letter] = adj == null ? 0
-                                        : adj.opt;
-                            }
-                            if (lsCount > 0) {
-                                letterAdjust[letter] += textArea.getTextLetterSpaceAdjust();
-                                lsCount--;
-                            }
-                            letter++;
-                        }
+                textArea = new TextArea(width.getStretch(), width.getShrink(),
+                        adjust);
+            }
+        }
+
+        private void setInlineProgressionDimension() {
+            textArea.setIPD(width.getOpt() + adjust);
+        }
+
+        private void calcBlockProgressionDimension() {
+            blockProgressionDimension = font.getAscender() - font.getDescender();
+        }
+
+        private void setBlockProgressionDimension() {
+            textArea.setBPD(blockProgressionDimension);
+        }
+
+        private void setBaselineOffset() {
+            textArea.setBaselineOffset(font.getAscender());
+        }
+
+        private void setOffset() {
+            if (blockProgressionDimension == alignmentContext.getHeight()) {
+                textArea.setOffset(0);
+            } else {
+                textArea.setOffset(alignmentContext.getOffset());
+            }
+        }
+
+        /**
+         * Sets the text of the TextArea, split into words and spaces.
+         */
+        private void setText() {
+            int wordStartIndex = -1;
+            int wordCharLength = 0;
+            for (int wordIndex = firstIndex; wordIndex <= lastIndex; wordIndex++) {
+                areaInfo = getAreaInfo(wordIndex);
+                if (areaInfo.isSpace) {
+                    addSpaces();
+                } else {
+                    // areaInfo stores information about a word fragment
+                    if (wordStartIndex == -1) {
+                        // here starts a new word
+                        wordStartIndex = wordIndex;
+                        wordCharLength = 0;
                     }
-                    // String wordChars = new String(textArray, wordStartIndex, len);
-                    if (isLastArea
-                        && i == lastIndex
-                        && areaInfo.isHyphenated) {
-                        // add the hyphenation character
-                        wordChars.append(this.foText.getCommonHyphenation().getHyphChar(font));
+                    wordCharLength += areaInfo.getCharLength();
+                    if (isWordEnd(wordIndex)) {
+                        addWord(wordStartIndex, wordIndex, wordCharLength);
+                        wordStartIndex = -1;
                     }
-                    textArea.addWord(wordChars.toString(), 0, letterAdjust);
-                    wordStartIndex = -1;
                 }
             }
         }
-        TraitSetter.addFontTraits(textArea, font);
-        textArea.addTrait(Trait.COLOR, this.foText.getColor());
-        TraitSetter.addPtr(textArea, getPtr()); // used for accessibility
-        TraitSetter.addTextDecoration(textArea, this.foText.getTextDecoration());
 
-        return textArea;
+        private boolean isWordEnd(int areaInfoIndex) {
+            return areaInfoIndex == lastIndex || getAreaInfo(areaInfoIndex + 1).isSpace;
+        }
+
+        private void addWord(int startIndex, int endIndex, int charLength) {
+            if (isHyphenated(endIndex)) {
+                charLength++;
+            }
+            initWord(charLength);
+            for (int i = startIndex; i <= endIndex; i++) {
+                AreaInfo wordAreaInfo = getAreaInfo(i);
+                addWordChars(wordAreaInfo);
+                addLetterAdjust(wordAreaInfo);
+            }
+            if (isHyphenated(endIndex)) {
+                addHyphenationChar();
+            }
+            textArea.addWord(wordChars.toString(), 0, letterAdjust);
+        }
+
+        private void initWord(int charLength) {
+            wordChars = new StringBuffer(charLength);
+            letterAdjust = new int[charLength];
+            letterAdjustIndex = 0;
+        }
+
+        private boolean isHyphenated(int endIndex) {
+            return isLastArea && endIndex == lastIndex && areaInfo.isHyphenated;
+        }
+
+        private void addHyphenationChar() {
+            wordChars.append(foText.getCommonHyphenation().getHyphChar(font));
+        }
+
+        private void addWordChars(AreaInfo wordAreaInfo) {
+            for (int i = wordAreaInfo.startIndex; i < wordAreaInfo.breakIndex; i++) {
+                wordChars.append(foText.charAt(i));
+            }
+        }
+
+        private void addLetterAdjust(AreaInfo wordAreaInfo) {
+            int letterSpaceCount = wordAreaInfo.letterSpaceCount;
+            for (int i = wordAreaInfo.startIndex; i < wordAreaInfo.breakIndex; i++) {
+                if (letterAdjustIndex > 0) {
+                    MinOptMax adj = letterAdjustArray[i];
+                    letterAdjust[letterAdjustIndex] = adj == null ? 0 : adj.getOpt();
+                }
+                if (letterSpaceCount > 0) {
+                    letterAdjust[letterAdjustIndex] += textArea.getTextLetterSpaceAdjust();
+                    letterSpaceCount--;
+                }
+                letterAdjustIndex++;
+            }
+        }
+
+        /**
+         * The <code>AreaInfo</code> stores information about spaces.
+         * <p/>
+         * Add the spaces - except zero-width spaces - to the TextArea.
+         */
+        private void addSpaces() {
+            for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+                char spaceChar = foText.charAt(i);
+                if (!CharUtilities.isZeroWidthSpace(spaceChar)) {
+                    textArea.addSpace(spaceChar, 0, CharUtilities.isAdjustableSpace(spaceChar));
+                }
+            }
+        }
     }
 
     /**
@@ -520,7 +586,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      * @return ptr of fobj
      */
     private String getPtr() {
-        FObj fobj = this.parentLM.getFObj();
+        FObj fobj = parentLayoutManager.getFObj();
         if (fobj instanceof StructurePointerPropertySet) {
             return (((StructurePointerPropertySet) fobj).getPtr());
         } else {
@@ -529,11 +595,15 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         }
     }
 
-    private void addToLetterAdjust(final int index, final int width) {
-        if (this.letterAdjustArray[index] == null) {
-            this.letterAdjustArray[index] = new MinOptMax(width);
+    private AreaInfo getAreaInfo(int index) {
+        return (AreaInfo) areaInfos.get(index);
+    }
+
+    private void addToLetterAdjust(int index, int width) {
+        if (letterAdjustArray[index] == null) {
+            letterAdjustArray[index] = MinOptMax.getInstance(width);
         } else {
-            this.letterAdjustArray[index].add(width);
+            letterAdjustArray[index] = letterAdjustArray[index].plus(width);
         }
     }
 
@@ -544,32 +614,33 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
      */
     private static boolean isSpace(final char ch) {
         return ch == CharUtilities.SPACE
-            || CharUtilities.isNonBreakableSpace(ch)
-            || CharUtilities.isFixedWidthSpace(ch);
+                || CharUtilities.isNonBreakableSpace(ch)
+                || CharUtilities.isFixedWidthSpace(ch);
     }
 
     /** {@inheritDoc} */
     public List getNextKnuthElements(final LayoutContext context, final int alignment) {
-        this.lineStartBAP = context.getLineStartBorderAndPaddingWidth();
-        this.lineEndBAP = context.getLineEndBorderAndPaddingWidth();
-        this.alignmentContext = context.getAlignmentContext();
+        lineStartBAP = context.getLineStartBorderAndPaddingWidth();
+        lineEndBAP = context.getLineEndBorderAndPaddingWidth();
+        alignmentContext = context.getAlignmentContext();
 
         final List returnList = new LinkedList();
         KnuthSequence sequence = new InlineKnuthSequence();
-        AreaInfo ai = null;
-        AreaInfo prevAi = null;
+        AreaInfo areaInfo = null;
+        AreaInfo prevAreaInfo = null;
         returnList.add(sequence);
 
-        final LineBreakStatus lbs = new LineBreakStatus();
-        this.thisStart = this.nextStart;
+        LineBreakStatus lineBreakStatus = new LineBreakStatus();
+        thisStart = nextStart;
         boolean inWord = false;
         boolean inWhitespace = false;
         char ch = 0;
-        while (this.nextStart < this.foText.length()) {
-            ch = this.foText.charAt(this.nextStart);
+        while (nextStart < foText.length()) {
+            ch = foText.charAt(nextStart);
             boolean breakOpportunity = false;
-            final byte breakAction = this.keepTogether ? LineBreakStatus.PROHIBITED_BREAK
-                    : lbs.nextChar(ch);
+            byte breakAction = keepTogether
+                    ? LineBreakStatus.PROHIBITED_BREAK
+                    : lineBreakStatus.nextChar(ch);
             switch (breakAction) {
                 case LineBreakStatus.COMBINING_PROHIBITED_BREAK:
                 case LineBreakStatus.PROHIBITED_BREAK:
@@ -589,62 +660,58 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                         || TextLayoutManager.isSpace(ch)
                         || CharUtilities.isExplicitBreak(ch)) {
                     // this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN
-                    prevAi = this.processWord(alignment, sequence, prevAi, ch,
+                    prevAreaInfo = processWord(alignment, sequence, prevAreaInfo, ch,
                             breakOpportunity, true);
                 }
             } else if (inWhitespace) {
                 if (ch != CharUtilities.SPACE || breakOpportunity) {
-                    prevAi = this.processWhitespace(alignment, sequence,
-                            breakOpportunity);
+                    prevAreaInfo = processWhitespace(alignment, sequence, breakOpportunity);
                 }
             } else {
-                if (ai != null) {
-                    prevAi = ai;
-                    ai = this.processLeftoverAi(alignment, sequence, ai, ch,
+                if (areaInfo != null) {
+                    prevAreaInfo = areaInfo;
+                    processLeftoverAreaInfo(alignment, sequence, areaInfo,
                             ch == CharUtilities.SPACE || breakOpportunity);
+                    areaInfo = null;
                 }
                 if (breakAction == LineBreakStatus.EXPLICIT_BREAK) {
-                    sequence = this.processLinebreak(returnList, sequence);
+                    sequence = processLinebreak(returnList, sequence);
                 }
             }
 
             if (ch == CharUtilities.SPACE
-                    && this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE
+                    && foText.getWhitespaceTreatment() == Constants.EN_PRESERVE
                     || ch == CharUtilities.NBSPACE) {
                 // preserved space or non-breaking space:
                 // create the AreaInfo object
-                ai = new AreaInfo(this.nextStart, this.nextStart + 1,
-                        1, 0, this.wordSpaceIPD, false, true,
-                        breakOpportunity, this.spaceFont);
-                this.thisStart = this.nextStart + 1;
+                areaInfo = new AreaInfo(nextStart, nextStart + 1, 1, 0, wordSpaceIPD, false, true,
+                        breakOpportunity, spaceFont);
+                thisStart = nextStart + 1;
             } else if (CharUtilities.isFixedWidthSpace(ch) || CharUtilities.isZeroWidthSpace(ch)) {
                 // create the AreaInfo object
-                final Font font = FontSelector.selectFontForCharacterInText(ch,
-                        this.foText, this);
-                final MinOptMax ipd = new MinOptMax(font.getCharWidth(ch));
-                ai = new AreaInfo(this.nextStart, this.nextStart + 1,
-                        0, 0, ipd, false, true,
+                Font font = FontSelector.selectFontForCharacterInText(ch, foText, this);
+                MinOptMax ipd = MinOptMax.getInstance(font.getCharWidth(ch));
+                areaInfo = new AreaInfo(nextStart, nextStart + 1, 0, 0, ipd, false, true,
                         breakOpportunity, font);
-                this.thisStart = this.nextStart + 1;
+                thisStart = nextStart + 1;
             } else if (CharUtilities.isExplicitBreak(ch)) {
                 //mandatory break-character: only advance index
-                this.thisStart = this.nextStart + 1;
+                thisStart = nextStart + 1;
             }
 
-            inWord = !TextLayoutManager.isSpace(ch)
-                    && !CharUtilities.isExplicitBreak(ch);
+            inWord = !TextLayoutManager.isSpace(ch) && !CharUtilities.isExplicitBreak(ch);
             inWhitespace = ch == CharUtilities.SPACE
-                    && this.foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
-            this.nextStart++;
-        } // end of while
+                    && foText.getWhitespaceTreatment() != Constants.EN_PRESERVE;
+            nextStart++;
+        }
 
         // Process any last elements
         if (inWord) {
-            this.processWord(alignment, sequence, prevAi, ch, false, false);
+            processWord(alignment, sequence, prevAreaInfo, ch, false, false);
         } else if (inWhitespace) {
-            this.processWhitespace(alignment, sequence, true);
-        } else if (ai != null) {
-            this.processLeftoverAi(alignment, sequence, ai, ch,
+            processWhitespace(alignment, sequence, true);
+        } else if (areaInfo != null) {
+            processLeftoverAreaInfo(alignment, sequence, areaInfo,
                     ch == CharUtilities.ZERO_WIDTH_SPACE);
         } else if (CharUtilities.isExplicitBreak(ch)) {
             this.processLinebreak(returnList, sequence);
@@ -655,7 +722,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             ListUtil.removeLast(returnList);
         }
 
-        this.setFinished(true);
+        setFinished(true);
         if (returnList.isEmpty()) {
             return null;
         } else {
@@ -663,12 +730,9 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         }
     }
 
-    private KnuthSequence processLinebreak(final List returnList,
-            KnuthSequence sequence) {
-        if (this.lineEndBAP != 0) {
-            sequence.add(
-                    new KnuthGlue(this.lineEndBAP, 0, 0,
-                                  this.auxiliaryPosition, true));
+    private KnuthSequence processLinebreak(List returnList, KnuthSequence sequence) {
+        if (lineEndBAP != 0) {
+            sequence.add(new KnuthGlue(lineEndBAP, 0, 0, auxiliaryPosition, true));
         }
         sequence.endSequence();
         sequence = new InlineKnuthSequence();
@@ -676,32 +740,29 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         return sequence;
     }
 
-    private AreaInfo processLeftoverAi(final int alignment,
-            final KnuthSequence sequence, AreaInfo ai, final char ch,
-            final boolean breakOpportunityAfter) {
-        this.vecAreaInfo.add(ai);
-        ai.breakOppAfter = breakOpportunityAfter;
-        this.addElementsForASpace(sequence, alignment, ai, this.vecAreaInfo.size() - 1);
-        ai = null;
-        return ai;
+    private void processLeftoverAreaInfo(int alignment,
+                                         KnuthSequence sequence, AreaInfo areaInfo,
+                                         boolean breakOpportunityAfter) {
+        areaInfos.add(areaInfo);
+        areaInfo.breakOppAfter = breakOpportunityAfter;
+        addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
     }
 
     private AreaInfo processWhitespace(final int alignment,
             final KnuthSequence sequence, final boolean breakOpportunity) {
         // End of whitespace
         // create the AreaInfo object
-        AreaInfo ai = new AreaInfo(this.thisStart, this.nextStart,
-                this.nextStart - this.thisStart, 0,
-                MinOptMax.multiply(this.wordSpaceIPD, this.nextStart
-                        - this.thisStart), false, true,
-                breakOpportunity, this.spaceFont);
-        this.vecAreaInfo.add(ai);
+        assert nextStart >= thisStart;
+        AreaInfo areaInfo = new AreaInfo(thisStart, nextStart, nextStart - thisStart, 0,
+                wordSpaceIPD.mult(nextStart - thisStart), false, true, breakOpportunity, spaceFont);
+
+        areaInfos.add(areaInfo);
 
         // create the elements
-        this.addElementsForASpace(sequence, alignment, ai, this.vecAreaInfo.size() - 1);
+        addElementsForASpace(sequence, alignment, areaInfo, areaInfos.size() - 1);
 
-        this.thisStart = this.nextStart;
-        return ai;
+        thisStart = nextStart;
+        return areaInfo;
     }
 
     private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
@@ -709,39 +770,36 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             final boolean checkEndsWithHyphen) {
 
         //Word boundary found, process widths and kerning
-        int lastIndex = this.nextStart;
-        while (lastIndex > 0
-                && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
+        int lastIndex = nextStart;
+        while (lastIndex > 0 && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
             lastIndex--;
         }
         final boolean endsWithHyphen = checkEndsWithHyphen
                 && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
-        final Font font = FontSelector
-                .selectFontForCharactersInText(foText,
-                        this.thisStart, lastIndex, foText, this);
-        final int wordLength = lastIndex - this.thisStart;
-        final boolean kerning = font.hasKerning();
-        final MinOptMax wordIPD = new MinOptMax(0);
-        for (int i = this.thisStart; i < lastIndex; i++) {
-            final char currentChar = foText.charAt(i);
+        Font font = FontSelector.selectFontForCharactersInText(foText, thisStart, lastIndex, foText, this);
+        int wordLength = lastIndex - thisStart;
+        boolean kerning = font.hasKerning();
+        MinOptMax wordIPD = MinOptMax.ZERO;
+        for (int i = thisStart; i < lastIndex; i++) {
+            char currentChar = foText.charAt(i);
 
             //character width
-            final int charWidth = font.getCharWidth(currentChar);
-            wordIPD.add(charWidth);
+            int charWidth = font.getCharWidth(currentChar);
+            wordIPD = wordIPD.plus(charWidth);
 
             //kerning
             if (kerning) {
                 int kern = 0;
-                if (i > this.thisStart) {
-                    final char previousChar = foText.charAt(i - 1);
+                if (i > thisStart) {
+                    char previousChar = foText.charAt(i - 1);
                     kern = font.getKernValue(previousChar, currentChar);
                 } else if (prevAreaInfo != null && !prevAreaInfo.isSpace && prevAreaInfo.breakIndex > 0) {
-                    final char previousChar = foText.charAt(prevAreaInfo.breakIndex - 1);
+                    char previousChar = foText.charAt(prevAreaInfo.breakIndex - 1);
                     kern = font.getKernValue(previousChar, currentChar);
                 }
                 if (kern != 0) {
-                    this.addToLetterAdjust(i, kern);
-                    wordIPD.add(kern);
+                    addToLetterAdjust(i, kern);
+                    wordIPD = wordIPD.plus(kern);
                 }
             }
         }
@@ -752,7 +810,7 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                 && endsWithHyphen) {
             final int kern = font.getKernValue(foText.charAt(lastIndex - 1), ch);
             if (kern != 0) {
-                this.addToLetterAdjust(lastIndex, kern);
+                addToLetterAdjust(lastIndex, kern);
                 //TODO: add kern to wordIPD?
             }
         }
@@ -763,21 +821,21 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         if (breakOpportunity && !TextLayoutManager.isSpace(ch)) {
             iLetterSpaces++;
         }
-        wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces));
+        assert iLetterSpaces >= 0;
+        wordIPD = wordIPD.plus(letterSpaceIPD.mult(iLetterSpaces));
 
         // create the AreaInfo object
-        AreaInfo areaInfo = new AreaInfo(this.thisStart, lastIndex, 0,
+        AreaInfo areaInfo = new AreaInfo(thisStart, lastIndex, 0,
                 iLetterSpaces, wordIPD,
                 endsWithHyphen,
                 false, breakOpportunity, font);
         prevAreaInfo = areaInfo;
-        this.vecAreaInfo.add(areaInfo);
-        this.tempStart = this.nextStart;
+        areaInfos.add(areaInfo);
+        tempStart = nextStart;
 
         //add the elements
-        this.addElementsForAWordFragment(sequence, alignment, areaInfo,
-                this.vecAreaInfo.size() - 1, this.letterSpaceIPD);
-        this.thisStart = this.nextStart;
+        addElementsForAWordFragment(sequence, alignment, areaInfo, areaInfos.size() - 1);
+        thisStart = nextStart;
 
         return prevAreaInfo;
     }
@@ -788,49 +846,39 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
         // look at the Position stored in the first element in oldList
         // which is always a box
         ListIterator oldListIterator = oldList.listIterator();
-        final KnuthElement el = (KnuthElement)oldListIterator.next();
-        final LeafPosition pos = (LeafPosition) ((KnuthBox) el).getPosition();
-        final int idx = pos.getLeafPos();
+        KnuthElement knuthElement = (KnuthElement) oldListIterator.next();
+        LeafPosition pos = (LeafPosition) ((KnuthBox) knuthElement).getPosition();
+        int index = pos.getLeafPos();
         //element could refer to '-1' position, for non-collapsed spaces (?)
-        if (idx > -1) {
-            final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(idx);
-            ai.letterSpaceCount++;
-            ai.areaIPD.add(this.letterSpaceIPD);
-            if (TextLayoutManager.BREAK_CHARS.indexOf(this.foText.charAt(this.tempStart - 1)) >= 0) {
+        if (index > -1) {
+            AreaInfo areaInfo = getAreaInfo(index);
+            areaInfo.letterSpaceCount++;
+            areaInfo.addToAreaIPD(letterSpaceIPD);
+            if (TextLayoutManager.BREAK_CHARS.indexOf(foText.charAt(tempStart - 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,
-                                                     this.auxiliaryPosition, false));
-                oldListIterator.add(new KnuthGlue(this.letterSpaceIPD.opt,
-                                           this.letterSpaceIPD.max - this.letterSpaceIPD.opt,
-                                           this.letterSpaceIPD.opt - this.letterSpaceIPD.min,
-                                           this.auxiliaryPosition, false));
-            } else if (this.letterSpaceIPD.min == this.letterSpaceIPD.max) {
+                        auxiliaryPosition, false));
+                oldListIterator.add(new KnuthGlue(letterSpaceIPD, auxiliaryPosition, false));
+            } else if (letterSpaceIPD.isStiff()) {
                 // constant letter space: replace the box
-                oldListIterator.set(new KnuthInlineBox(ai.areaIPD.opt,
-                        this.alignmentContext, pos, false));
+                oldListIterator.set(new KnuthInlineBox(areaInfo.areaIPD.getOpt(),
+                        alignmentContext, 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.letterSpaceCount * this.letterSpaceIPD.opt,
-                                ai.letterSpaceCount
-                                        * (this.letterSpaceIPD.max - this.letterSpaceIPD.opt),
-                                ai.letterSpaceCount
-                                        * (this.letterSpaceIPD.opt - this.letterSpaceIPD.min),
-                                this.auxiliaryPosition, true));
+                oldListIterator.set(new KnuthGlue(letterSpaceIPD.mult(areaInfo.letterSpaceCount),
+                        auxiliaryPosition, true));
             }
         }
         return oldList;
     }
 
     /**
-     * remove the AreaInfo object represented by the given elements,
-     * so that it won't generate any element when getChangedKnuthElements
-     * will be called
+     * Removes the <code>AreaInfo</code> object represented by the given elements, so that it won't
+     * generate any element when <code>getChangedKnuthElements</code> is called.
      *
      * @param oldList the elements representing the word space
      */
@@ -848,99 +896,91 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             oldListIterator.next();
             oldListIterator.next();
         }
-        final int leafValue = ((LeafPosition) ((KnuthElement) oldListIterator
-                .next()).getPosition()).getLeafPos();
+        KnuthElement knuthElement = (KnuthElement) oldListIterator.next();
+        int leafValue = ((LeafPosition) knuthElement.getPosition()).getLeafPos();
         // only the last word space can be a trailing space!
-        if (leafValue == this.vecAreaInfo.size() - 1) {
-            this.vecAreaInfo.remove(leafValue);
+        if (leafValue == areaInfos.size() - 1) {
+            areaInfos.remove(leafValue);
         } else {
             TextLayoutManager.LOG.error("trying to remove a non-trailing word space");
         }
     }
 
-    /** {@inheritDoc} */
-    public void hyphenate(final Position pos, final HyphContext hc) {
-        final AreaInfo ai
-            = (AreaInfo) this.vecAreaInfo.get(((LeafPosition) pos).getLeafPos());
-        int startIndex = ai.startIndex;
+    /**
+     * {@inheritDoc}
+     */
+    public void hyphenate(Position pos, HyphContext hyphContext) {
+        AreaInfo areaInfo = getAreaInfo(((LeafPosition) pos).getLeafPos());
+        int startIndex = areaInfo.startIndex;
         int stopIndex;
         boolean nothingChanged = true;
-        final Font font = ai.font;
+        Font font = areaInfo.font;
 
-        while (startIndex < ai.breakIndex) {
-            final MinOptMax newIPD = new MinOptMax(0);
+        while (startIndex < areaInfo.breakIndex) {
+            MinOptMax newIPD = MinOptMax.ZERO;
             boolean hyphenFollows;
 
-            stopIndex = startIndex + hc.getNextHyphPoint();
-            if (hc.hasMoreHyphPoints() && stopIndex <= ai.breakIndex) {
+            stopIndex = startIndex + hyphContext.getNextHyphPoint();
+            if (hyphContext.hasMoreHyphPoints() && stopIndex <= areaInfo.breakIndex) {
                 // stopIndex is the index of the first character
                 // after a hyphenation point
                 hyphenFollows = true;
             } else {
                 // there are no more hyphenation points,
-                // or the next one is after ai.breakIndex
+                // or the next one is after areaInfo.breakIndex
                 hyphenFollows = false;
-                stopIndex = ai.breakIndex;
+                stopIndex = areaInfo.breakIndex;
             }
 
-            hc.updateOffset(stopIndex - startIndex);
+            hyphContext.updateOffset(stopIndex - startIndex);
 
             //log.info("Word: " + new String(textArray, startIndex, stopIndex - startIndex));
             for (int i = startIndex; i < stopIndex; i++) {
-                final char c = this.foText.charAt(i);
-                newIPD.add(new MinOptMax(font.getCharWidth(c)));
+                char ch = foText.charAt(i);
+                newIPD = newIPD.plus(font.getCharWidth(ch));
                 //if (i > startIndex) {
                 if (i < stopIndex) {
-                    MinOptMax la = this.letterAdjustArray[i + 1];
+                    MinOptMax letterAdjust = letterAdjustArray[i + 1];
                     if (i == stopIndex - 1 && hyphenFollows) {
                         //the letter adjust here needs to be handled further down during
                         //element generation because it depends on hyph/no-hyph condition
-                        la = null;
+                        letterAdjust = null;
                     }
-                    if (la != null) {
-                        newIPD.add(la);
+                    if (letterAdjust != null) {
+                        newIPD = newIPD.plus(letterAdjust);
                     }
                 }
             }
+
             // add letter spaces
-            final boolean isWordEnd
-                = stopIndex == ai.breakIndex
-                && ai.letterSpaceCount < ai.breakIndex - ai.startIndex;
-            newIPD.add(MinOptMax.multiply(this.letterSpaceIPD,
-                                          (isWordEnd
-                                           ? stopIndex - startIndex - 1
-                                           : stopIndex - startIndex)));
-
-            if (!(nothingChanged
-                  && stopIndex == ai.breakIndex
-                  && !hyphenFollows)) {
+            boolean isWordEnd = stopIndex == areaInfo.breakIndex && areaInfo.letterSpaceCount < areaInfo.getCharLength();
+            int letterSpaceCount = isWordEnd ? stopIndex - startIndex - 1 : stopIndex - startIndex;
+
+            assert letterSpaceCount >= 0;
+            newIPD = newIPD.plus(letterSpaceIPD.mult(letterSpaceCount));
+
+            if (!(nothingChanged && stopIndex == areaInfo.breakIndex && !hyphenFollows)) {
                 // the new AreaInfo object is not equal to the old one
-                if (this.changeList == null) {
-                    this.changeList = new LinkedList();
-                }
-                this.changeList.add(new PendingChange(new AreaInfo(
-                        startIndex, stopIndex, 0,
-                        (isWordEnd ? stopIndex - startIndex - 1
-                                : stopIndex - startIndex), newIPD,
-                        hyphenFollows, false, false, font),
+                changeList.add(new PendingChange(new AreaInfo(startIndex, stopIndex, 0,
+                        letterSpaceCount, newIPD, hyphenFollows, false, false, font),
                         ((LeafPosition) pos).getLeafPos()));
                 nothingChanged = false;
             }
             startIndex = stopIndex;
         }
-        this.hasChanged = (this.hasChanged || !nothingChanged);
+        hasChanged |= !nothingChanged;
     }
 
     /** {@inheritDoc} */
     public boolean applyChanges(final List oldList) {
-        this.setFinished(false);
+        setFinished(false);
 
-        if (this.changeList != null && !this.changeList.isEmpty()) {
+        if (!changeList.isEmpty()) {
             int areaInfosAdded = 0;
             int areaInfosRemoved = 0;
             int oldIndex = -1, changeIndex;
             PendingChange currChange;
-            final ListIterator changeListIterator = this.changeList.listIterator();
+            ListIterator changeListIterator = changeList.listIterator();
             while (changeListIterator.hasNext()) {
                 currChange = (PendingChange) changeListIterator.next();
                 if (currChange.index == oldIndex) {
@@ -951,111 +991,109 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
                     areaInfosAdded++;
                     oldIndex = currChange.index;
                     changeIndex = currChange.index + areaInfosAdded - areaInfosRemoved;
-                    this.vecAreaInfo.remove(changeIndex);
+                    areaInfos.remove(changeIndex);
                 }
-                this.vecAreaInfo.add(changeIndex, currChange.ai);
+                areaInfos.add(changeIndex, currChange.areaInfo);
             }
-            this.changeList.clear();
+            changeList.clear();
         }
 
-        this.returnedIndex = 0;
-        return this.hasChanged;
+        returnedIndex = 0;
+        return hasChanged;
     }
 
     /** {@inheritDoc} */
-    public List getChangedKnuthElements(final List oldList,
-                                              final int alignment) {
-        if (this.isFinished()) {
+    public List getChangedKnuthElements(final List oldList, final int alignment) {
+        if (isFinished()) {
             return null;
         }
 
         final LinkedList returnList = new LinkedList();
 
-        while (this.returnedIndex < this.vecAreaInfo.size()) {
-            final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(this.returnedIndex);
-            if (ai.wordSpaceCount == 0) {
-                // ai refers either to a word or a word fragment
-                this.addElementsForAWordFragment(returnList, alignment, ai,
-                        this.returnedIndex, this.letterSpaceIPD);
+        while (returnedIndex < areaInfos.size()) {
+            AreaInfo areaInfo = getAreaInfo(returnedIndex);
+            if (areaInfo.wordSpaceCount == 0) {
+                // areaInfo refers either to a word or a word fragment
+                addElementsForAWordFragment(returnList, alignment, areaInfo, returnedIndex);
             } else {
-                // ai refers to a space
-                this.addElementsForASpace(returnList, alignment, ai, this.returnedIndex);
+                // areaInfo refers to a space
+                addElementsForASpace(returnList, alignment, areaInfo, returnedIndex);
             }
-            this.returnedIndex++;
-        } // end of while
-        this.setFinished(true);
+            returnedIndex++;
+        }
+        setFinished(true);
         //ElementListObserver.observe(returnList, "text-changed", null);
         return returnList;
     }
 
-    /** {@inheritDoc} */
-    public void getWordChars(final StringBuffer sbChars, final Position pos) {
-        final int leafValue = ((LeafPosition) pos).getLeafPos();
+    /**
+     * {@inheritDoc}
+     */
+    public String getWordChars(Position pos) {
+        int leafValue = ((LeafPosition) pos).getLeafPos();
         if (leafValue != -1) {
-            final AreaInfo ai = (AreaInfo) this.vecAreaInfo.get(leafValue);
-            for (int i = ai.startIndex; i < ai.breakIndex; ++i) {
-                sbChars.append(this.foText.charAt(i));
+            AreaInfo areaInfo = getAreaInfo(leafValue);
+            StringBuffer buffer = new StringBuffer(areaInfo.getCharLength());
+            for (int i = areaInfo.startIndex; i < areaInfo.breakIndex; i++) {
+                buffer.append(foText.charAt(i));
             }
+            return buffer.toString();
+        } else {
+            return "";
         }
     }
 
-    private void addElementsForASpace(final List baseList,
-                                      final int alignment,
-                                      final AreaInfo ai,
-                                      final int leafValue) {
-        final LeafPosition mainPosition = new LeafPosition(this, leafValue);
+    private void addElementsForASpace(List baseList, int alignment, AreaInfo areaInfo,
+                                      int leafValue) {
+        LeafPosition mainPosition = new LeafPosition(this, leafValue);
 
-        if (!ai.breakOppAfter) {
+        if (!areaInfo.breakOppAfter) {
             // a non-breaking space
             if (alignment == Constants.EN_JUSTIFY) {
                 // the space can stretch and shrink, and must be preserved
                 // when starting a line
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max - ai.areaIPD.opt,
-                        ai.areaIPD.opt - ai.areaIPD.min, mainPosition, false));
+                baseList.add(makeAuxiliaryZeroWidthBox());
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(new KnuthGlue(areaInfo.areaIPD, mainPosition, false));
             } else {
                 // the space does not need to stretch or shrink, and must be
                 // preserved when starting a line
-                baseList.add(new KnuthInlineBox(ai.areaIPD.opt, null,
-                        mainPosition, true));
+                baseList.add(new KnuthInlineBox(areaInfo.areaIPD.getOpt(), null, mainPosition,
+                        true));
             }
         } else {
-            if (this.foText.charAt(ai.startIndex) != CharUtilities.SPACE
-                    || this.foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
+            if (foText.charAt(areaInfo.startIndex) != CharUtilities.SPACE
+                    || foText.getWhitespaceTreatment() == Constants.EN_PRESERVE) {
                 // a breaking space that needs to be preserved
-                this.addElementsForBreakingSpace(baseList, alignment, ai,
-                                this.auxiliaryPosition, 0, mainPosition,
-                                ai.areaIPD.opt, true);
+                baseList.addAll(getElementsForBreakingSpace(alignment, areaInfo, auxiliaryPosition, 0,
+                        mainPosition, areaInfo.areaIPD.getOpt(), true));
             } else {
                 // a (possible block) of breaking spaces
-                this.addElementsForBreakingSpace(baseList, alignment, ai,
-                                mainPosition, ai.areaIPD.opt,
-                                this.auxiliaryPosition, 0, false);
+                baseList.addAll(getElementsForBreakingSpace(alignment, areaInfo, mainPosition,
+                        areaInfo.areaIPD.getOpt(), auxiliaryPosition, 0, false));
             }
         }
     }
 
-    private void addElementsForBreakingSpace(final List baseList,
-            final int alignment, final AreaInfo ai, final Position pos2,
-            final int p2WidthOffset, final Position pos3,
-            final int p3WidthOffset, final boolean skipZeroCheck) {
+    private List getElementsForBreakingSpace(int alignment, AreaInfo areaInfo, Position pos2,
+                                             int p2WidthOffset, Position pos3,
+                                             int p3WidthOffset, boolean skipZeroCheck) {
+        List elements = new ArrayList();
+
         switch (alignment) {
         case EN_CENTER:
             // centered text:
             // if the second element is chosen as a line break these elements
             // add a constant amount of stretch at the end of a line and at the
             // beginning of the next one, otherwise they don't add any stretch
-            baseList.add(new KnuthGlue(this.lineEndBAP,
-                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                    this.auxiliaryPosition, false));
-            baseList.add(this.makeZeroWidthPenalty(0));
-            baseList.add(new KnuthGlue(p2WidthOffset
-                    - (this.lineStartBAP + this.lineEndBAP), -6
+            elements.add(new KnuthGlue(lineEndBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                    auxiliaryPosition, false));
+            elements.add(makeZeroWidthPenalty(0));
+            elements.add(new KnuthGlue(p2WidthOffset - (lineStartBAP + lineEndBAP), -6
                     * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos2, false));
-            baseList.add(this.makeAuxiliaryZeroWidthBox());
-            baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-            baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
+            elements.add(makeAuxiliaryZeroWidthBox());
+            elements.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+            elements.add(new KnuthGlue(lineStartBAP + p3WidthOffset,
                     3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos3, false));
             break;
 
@@ -1065,246 +1103,203 @@ public class TextLayoutManager extends LeafNodeLayoutManager {
             // if the second element is chosen as a line break these elements
             // add a constant amount of stretch at the end of a line, otherwise
             // they don't add any stretch
-            if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
-                baseList.add(new KnuthGlue(this.lineEndBAP,
-                        3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                        this.auxiliaryPosition, false));
-                baseList.add(this.makeZeroWidthPenalty(0));
-                baseList.add(new KnuthGlue(p2WidthOffset
-                                - (this.lineStartBAP + this.lineEndBAP), -3
-                                * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                pos2, false));
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
-                        0, 0, pos3, false));
+            if (skipZeroCheck || lineStartBAP != 0 || lineEndBAP != 0) {
+                elements.add(new KnuthGlue(lineEndBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, auxiliaryPosition, false));
+                elements.add(makeZeroWidthPenalty(0));
+                elements.add(new KnuthGlue(p2WidthOffset - (lineStartBAP + lineEndBAP), -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos2, false));
+                elements.add(makeAuxiliaryZeroWidthBox());
+                elements.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                elements.add(new KnuthGlue(lineStartBAP + p3WidthOffset, 0, 0, pos3, false));
             } else {
-                baseList.add(new KnuthGlue(0,
-                        3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                        this.auxiliaryPosition, false));
-                baseList.add(this.makeZeroWidthPenalty(0));
-                baseList.add(new KnuthGlue(ai.areaIPD.opt, -3
-                                * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                                pos2, false));
+                elements.add(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, auxiliaryPosition, false));
+                elements.add(makeZeroWidthPenalty(0));
+                elements.add(new KnuthGlue(areaInfo.areaIPD.getOpt(), -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0, pos2, false));
             }
             break;
 
         case EN_JUSTIFY:
             // justified text:
             // the stretch and shrink depends on the space width
-            if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
-                baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
-                        this.auxiliaryPosition, false));
-                baseList.add(this.makeZeroWidthPenalty(0));
-                baseList.add(new KnuthGlue(p2WidthOffset
-                        - (this.lineStartBAP + this.lineEndBAP), ai.areaIPD.max
-                        - ai.areaIPD.opt, ai.areaIPD.opt - ai.areaIPD.min,
-                        pos2, false));
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
-                        0, 0, pos3, false));
-            } else {
-                baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max
-                        - ai.areaIPD.opt, ai.areaIPD.opt - ai.areaIPD.min,
-                        pos2, false));
-            }
+            elements.addAll(getElementsForJustifiedText(areaInfo, pos2, p2WidthOffset, pos3,
+                    p3WidthOffset, skipZeroCheck, areaInfo.areaIPD.getShrink()));
             break;
 
         default:
             // last line justified, the other lines unjustified:
             // use only the space stretch
-            if (skipZeroCheck || this.lineStartBAP != 0 || this.lineEndBAP != 0) {
-                baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
-                        this.auxiliaryPosition, false));
-                baseList.add(this.makeZeroWidthPenalty(0));
-                baseList.add(new KnuthGlue(p2WidthOffset
-                        - (this.lineStartBAP + this.lineEndBAP), ai.areaIPD.max
-                        - ai.areaIPD.opt, 0, pos2, false));
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineStartBAP + p3WidthOffset,
-                        0, 0, pos3, false));
-            } else {
-                baseList.add(new KnuthGlue(ai.areaIPD.opt, ai.areaIPD.max
-                        - ai.areaIPD.opt, 0, pos2, false));
-            }
+            elements.addAll(getElementsForJustifiedText(areaInfo, pos2, p2WidthOffset, pos3,
+                    p3WidthOffset, skipZeroCheck, 0));
         }
+        return elements;
     }
 
-    private void addElementsForAWordFragment(final List baseList,
-                                             final int alignment,
-                                             final AreaInfo ai,
-                                             final int leafValue,
-                                             final MinOptMax letterSpaceWidth) {
+    private List getElementsForJustifiedText(AreaInfo areaInfo, Position pos2, int p2WidthOffset,
+                                             Position pos3, int p3WidthOffset, boolean skipZeroCheck,
+                                             int shrinkability) {
+
+        int stretchability = areaInfo.areaIPD.getStretch();
+
+        List elements = new ArrayList();
+        if (skipZeroCheck || lineStartBAP != 0 || lineEndBAP != 0) {
+            elements.add(new KnuthGlue(lineEndBAP, 0, 0, auxiliaryPosition, false));
+            elements.add(makeZeroWidthPenalty(0));
+            elements.add(new KnuthGlue(p2WidthOffset - (lineStartBAP + lineEndBAP),
+                    stretchability, shrinkability, pos2, false));
+            elements.add(makeAuxiliaryZeroWidthBox());
+            elements.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+            elements.add(new KnuthGlue(lineStartBAP + p3WidthOffset, 0, 0, pos3, false));
+        } else {
+            elements.add(new KnuthGlue(areaInfo.areaIPD.getOpt(), stretchability, shrinkability,
+                    pos2, false));
+        }
+        return elements;
+    }
 
-        final LeafPosition mainPosition = new LeafPosition(this, leafValue);
+    private void addElementsForAWordFragment(List baseList, int alignment, AreaInfo areaInfo,
+                                             int leafValue) {
+        LeafPosition mainPosition = new LeafPosition(this, leafValue);
 
         // if the last character of the word fragment is '-' or '/',
         // the fragment could end a line; in this case, it loses one
         // of its letter spaces;
-        final boolean suppressibleLetterSpace = ai.breakOppAfter && !ai.isHyphenated;
+        boolean suppressibleLetterSpace = areaInfo.breakOppAfter && !areaInfo.isHyphenated;
 
-        if (letterSpaceWidth.min == letterSpaceWidth.max) {
+        if (letterSpaceIPD.isStiff()) {
             // constant letter spacing
-            baseList.add(new KnuthInlineBox(
-                        suppressibleLetterSpace
-                                ? ai.areaIPD.opt - letterSpaceWidth.opt
-                                : ai.areaIPD.opt,
-                        this.alignmentContext,
-                        this.notifyPos(mainPosition), false));
+            baseList.add(new KnuthInlineBox(suppressibleLetterSpace
+                    ? areaInfo.areaIPD.getOpt() - letterSpaceIPD.getOpt()
+                    : areaInfo.areaIPD.getOpt(),
+                    alignmentContext, notifyPos(mainPosition), false));
         } else {
             // adjustable letter spacing
-            final int unsuppressibleLetterSpaces
-                = suppressibleLetterSpace ? ai.letterSpaceCount - 1 : ai.letterSpaceCount;
-            baseList.add
-                (new KnuthInlineBox(ai.areaIPD.opt
-                        - ai.letterSpaceCount * letterSpaceWidth.opt,
-                        this.alignmentContext,
-                        this.notifyPos(mainPosition), false));
-            baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-            baseList.add
-                (new KnuthGlue(unsuppressibleLetterSpaces * letterSpaceWidth.opt,
-                        unsuppressibleLetterSpaces * (letterSpaceWidth.max - letterSpaceWidth.opt),
-                        unsuppressibleLetterSpaces * (letterSpaceWidth.opt - letterSpaceWidth.min),
-                        this.auxiliaryPosition, true));
-            baseList.add(this.makeAuxiliaryZeroWidthBox());
+            int unsuppressibleLetterSpaces = suppressibleLetterSpace
+                    ? areaInfo.letterSpaceCount - 1
+                    : areaInfo.letterSpaceCount;
+            baseList.add(new KnuthInlineBox(areaInfo.areaIPD.getOpt()
+                    - areaInfo.letterSpaceCount * letterSpaceIPD.getOpt(),
+                            alignmentContext, notifyPos(mainPosition), false));
+            baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+            baseList.add(new KnuthGlue(letterSpaceIPD.mult(unsuppressibleLetterSpaces),
+                    auxiliaryPosition, true));
+            baseList.add(makeAuxiliaryZeroWidthBox());
         }
 
         // extra-elements if the word fragment is the end of a syllable,
         // or it ends with a character that can be used as a line break
-        if (ai.isHyphenated) {
+        if (areaInfo.isHyphenated) {
             MinOptMax widthIfNoBreakOccurs = null;
-            if (ai.breakIndex < this.foText.length()) {
+            if (areaInfo.breakIndex < foText.length()) {
                 //Add in kerning in no-break condition
-                widthIfNoBreakOccurs = this.letterAdjustArray[ai.breakIndex];
+                widthIfNoBreakOccurs = letterAdjustArray[areaInfo.breakIndex];
             }
-            //if (ai.breakIndex)
+            //if (areaInfo.breakIndex)
 
             // the word fragment ends at the end of a syllable:
             // if a break occurs the content width increases,
             // otherwise nothing happens
-            this.addElementsForAHyphen(baseList, alignment, this.hyphIPD,
-                    widthIfNoBreakOccurs, ai.breakOppAfter && ai.isHyphenated);
+            addElementsForAHyphen(baseList, alignment, hyphIPD, widthIfNoBreakOccurs,
+                    areaInfo.breakOppAfter && areaInfo.isHyphenated);
         } else if (suppressibleLetterSpace) {
             // the word fragment ends with a character that acts as a hyphen
             // if a break occurs the width does not increase,
             // otherwise there is one more letter space
-            this.addElementsForAHyphen(baseList, alignment, 0, letterSpaceWidth, true);
+            addElementsForAHyphen(baseList, alignment, 0, letterSpaceIPD, true);
         }
     }
 
-    // static final int SOFT_HYPHEN_PENALTY = KnuthPenalty.FLAGGED_PENALTY / 10;
-    private static final int SOFT_HYPHEN_PENALTY = 1;
+    private void addElementsForAHyphen(List baseList, int alignment, int widthIfBreakOccurs,
+                                       MinOptMax widthIfNoBreakOccurs, boolean unflagged) {
 
-    private void addElementsForAHyphen(final List baseList,
-                                       final int alignment,
-                                       final int widthIfBreakOccurs,
-                                       MinOptMax widthIfNoBreakOccurs,
-                                       final boolean unflagged) {
         if (widthIfNoBreakOccurs == null) {
-            widthIfNoBreakOccurs = TextLayoutManager.ZERO_MINOPTMAX;
+            widthIfNoBreakOccurs = MinOptMax.ZERO;
         }
 
         switch (alignment) {
-        case EN_CENTER :
+        case EN_CENTER:
             // centered text:
-            baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-            baseList.add(new KnuthGlue(this.lineEndBAP,
-                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                    this.auxiliaryPosition, true));
-            baseList.add(new KnuthPenalty(this.hyphIPD,
-                    unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
-                            : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
-                    this.auxiliaryPosition, false));
-            baseList.add(new KnuthGlue(-(this.lineEndBAP + this.lineStartBAP),
+            baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+            baseList.add(new KnuthGlue(lineEndBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                    auxiliaryPosition, true));
+            baseList.add(new KnuthPenalty(hyphIPD, unflagged
+                    ? TextLayoutManager.SOFT_HYPHEN_PENALTY
+                            : KnuthPenalty.FLAGGED_PENALTY, !unflagged, auxiliaryPosition, false));
+            baseList.add(new KnuthGlue(-(lineEndBAP + lineStartBAP),
                     -6 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                    this.auxiliaryPosition, false));
-            baseList.add(this.makeAuxiliaryZeroWidthBox());
-            baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-            baseList.add(new KnuthGlue(this.lineStartBAP,
-                    3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                    this.auxiliaryPosition, true));
+                    auxiliaryPosition, false));
+            baseList.add(makeAuxiliaryZeroWidthBox());
+            baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+            baseList.add(new KnuthGlue(lineStartBAP, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH,
+                    0, auxiliaryPosition, true));
             break;
 
-        case EN_START  : // fall through
-        case EN_END    :
+        case EN_START: // fall through
+        case EN_END:
             // left- or right-aligned text:
-            if (this.lineStartBAP != 0 || this.lineEndBAP != 0) {
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineEndBAP,
+            if (lineStartBAP != 0 || lineEndBAP != 0) {
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(new KnuthGlue(lineEndBAP,
                         3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                        this.auxiliaryPosition, false));
+                        auxiliaryPosition, false));
                 baseList.add(new KnuthPenalty(widthIfBreakOccurs,
                         unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
                                 : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
-                        this.auxiliaryPosition, false));
-                baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt
-                        - (this.lineStartBAP + this.lineEndBAP), -3
-                        * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                        this.auxiliaryPosition, false));
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineStartBAP, 0, 0,
-                                   this.auxiliaryPosition, false));
+                                auxiliaryPosition, false));
+                baseList.add(new KnuthGlue(widthIfNoBreakOccurs.getOpt()
+                        - (lineStartBAP + lineEndBAP),
+                        -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                        auxiliaryPosition, false));
+                baseList.add(makeAuxiliaryZeroWidthBox());
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(new KnuthGlue(lineStartBAP, 0, 0, auxiliaryPosition, false));
             } else {
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
                 baseList.add(new KnuthGlue(0, 3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                            this.auxiliaryPosition, false));
+                        auxiliaryPosition, false));
                 baseList.add(new KnuthPenalty(widthIfBreakOccurs,
                         unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
                                 : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
-                        this.auxiliaryPosition, false));
-                baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt,
-                            -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
-                            this.auxiliaryPosition, false));
+                                auxiliaryPosition, false));
+                baseList.add(new KnuthGlue(widthIfNoBreakOccurs.getOpt(),
+                        -3 * LineLayoutManager.DEFAULT_SPACE_WIDTH, 0,
+                        auxiliaryPosition, false));
             }
             break;
 
         default:
             // justified text, or last line justified:
             // just a flagged penalty
-            if (this.lineStartBAP != 0 || this.lineEndBAP != 0) {
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineEndBAP, 0, 0,
-                                   this.auxiliaryPosition, false));
+            if (lineStartBAP != 0 || lineEndBAP != 0) {
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(new KnuthGlue(lineEndBAP, 0, 0, auxiliaryPosition, false));
                 baseList.add(new KnuthPenalty(widthIfBreakOccurs,
                         unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
                                 : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
-                        this.auxiliaryPosition, false));
+                                auxiliaryPosition, false));
                 // extra elements representing a letter space that is suppressed
                 // if a break occurs
-                if (widthIfNoBreakOccurs.min != 0
-                    || widthIfNoBreakOccurs.max != 0) {
-                    baseList
-                            .add(new KnuthGlue(widthIfNoBreakOccurs.opt
-                                    - (this.lineStartBAP + this.lineEndBAP),
-                                    widthIfNoBreakOccurs.max
-                                            - widthIfNoBreakOccurs.opt,
-                                    widthIfNoBreakOccurs.opt
-                                            - widthIfNoBreakOccurs.min,
-                                    this.auxiliaryPosition, false));
+                if (widthIfNoBreakOccurs.isNonZero()) {
+                    baseList.add(new KnuthGlue(widthIfNoBreakOccurs.getOpt()
+                            - (lineStartBAP + lineEndBAP),
+                            widthIfNoBreakOccurs.getStretch(),
+                            widthIfNoBreakOccurs.getShrink(),
+                            auxiliaryPosition, false));
                 } else {
-                    baseList.add(new KnuthGlue(-(this.lineStartBAP + this.lineEndBAP), 0, 0,
-                                       this.auxiliaryPosition, false));
+                    baseList.add(new KnuthGlue(-(lineStartBAP + lineEndBAP), 0, 0,
+                            auxiliaryPosition, false));
                 }
-                baseList.add(this.makeAuxiliaryZeroWidthBox());
-                baseList.add(this.makeZeroWidthPenalty(KnuthElement.INFINITE));
-                baseList.add(new KnuthGlue(this.lineStartBAP, 0, 0,
-                                   this.auxiliaryPosition, false));
+                baseList.add(makeAuxiliaryZeroWidthBox());
+                baseList.add(makeZeroWidthPenalty(KnuthElement.INFINITE));
+                baseList.add(new KnuthGlue(lineStartBAP, 0, 0,
+                        auxiliaryPosition, false));
             } else {
                 baseList.add(new KnuthPenalty(widthIfBreakOccurs,
                         unflagged ? TextLayoutManager.SOFT_HYPHEN_PENALTY
                                 : KnuthPenalty.FLAGGED_PENALTY, !unflagged,
-                        this.auxiliaryPosition, false));
+                                auxiliaryPosition, false));
                 // extra elements representing a letter space that is suppressed
                 // if a break occurs
-                if (widthIfNoBreakOccurs.min != 0
-                    || widthIfNoBreakOccurs.max != 0) {
-                    baseList.add(new KnuthGlue(widthIfNoBreakOccurs.opt,
-                                widthIfNoBreakOccurs.max - widthIfNoBreakOccurs.opt,
-                                widthIfNoBreakOccurs.opt - widthIfNoBreakOccurs.min,
-                                this.auxiliaryPosition, false));
+                if (widthIfNoBreakOccurs.isNonZero()) {
+                    baseList.add(new KnuthGlue(widthIfNoBreakOccurs, auxiliaryPosition, false));
                 }
             }
         }
index 97f07da544ad30e03333e8846af0a77594a0da47..4b93bcdacec28deeb543f97e473a791e51009318 100644 (file)
@@ -28,8 +28,6 @@ import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.TraitSetter;
 
-import java.util.LinkedList;
-
 /**
  * This is the layout manager for the fo:wrapper formatting object.
  */
@@ -67,14 +65,14 @@ public class WrapperLayoutManager extends LeafNodeLayoutManager {
     public void addAreas(PositionIterator posIter, LayoutContext context) {
         if (fobj.hasId()) {
             addId();
-            if (parentLM instanceof BlockStackingLayoutManager
-                    && !(parentLM instanceof BlockLayoutManager)) {
+            if (parentLayoutManager instanceof BlockStackingLayoutManager
+                    && !(parentLayoutManager instanceof BlockLayoutManager)) {
                 Block helperBlock = new Block();
                 TraitSetter.setProducerID(helperBlock, fobj.getId());
-                parentLM.addChildArea(helperBlock);
+                parentLayoutManager.addChildArea(helperBlock);
             } else {
                 InlineArea area = getEffectiveArea();
-                parentLM.addChildArea(area);
+                parentLayoutManager.addChildArea(area);
             }
         }
         while (posIter.hasNext()) {
index a9f2eeb27badd64b4289e622faf22b4af7cd3ff7..8ab79d2c4a05ce224779f630df8dc904248637ca 100644 (file)
@@ -154,7 +154,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
         // if this will create the first block area in a page
         // and display-align is after or center, add space before
         if (layoutContext.getSpaceBefore() > 0) {
-            addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+            addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
         }
 
         addId();
@@ -241,7 +241,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
 
             // Set up dimensions
             // Must get dimensions from parent area
-            /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
 
             // set traits
             TraitSetter.setProducerID(curBlockArea, getListBlockFO().getId());
index 7fd2219ea1199055155f8cadca749d3341c30329..246c570948ed589341deffa3cac0a49a1ca0f8f3 100644 (file)
@@ -201,7 +201,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager {
             TraitSetter.setProducerID(curBlockArea, getPartFO().getId());
 
             // Set up dimensions
-            Area parentArea = parentLM.getParentArea(curBlockArea);
+            Area parentArea = parentLayoutManager.getParentArea(curBlockArea);
             int referenceIPD = parentArea.getIPD();
             curBlockArea.setIPD(referenceIPD);
             // Get reference IPD from parentArea
index 9848584c047f9e07bf9cb6fab5638391e0d4f686..206d0ae1c8bf720f39817db210d1ecddb1eab593 100644 (file)
@@ -604,7 +604,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
             curBlockArea = new Block();
 
             // Set up dimensions
-            /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
 
             // set traits
             TraitSetter.setProducerID(curBlockArea, getListItemFO().getId());
index abcde41c75ca7e9536d89214076e1c0cbc301f00..36d42dbbea9f0c43c2cad019cecfe0df4dca9476 100644 (file)
@@ -38,7 +38,6 @@ import org.apache.fop.layoutmgr.KnuthBlockBox;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthPenalty;
-import org.apache.fop.layoutmgr.MinOptMaxUtil;
 import org.apache.fop.traits.MinOptMax;
 
 /**
@@ -211,8 +210,7 @@ class ActiveCell {
         bpAfterNormal = paddingAfterNormal + pgu.getAfterBorderWidth(ConditionalBorder.NORMAL);
         bpAfterTrailing = paddingAfterTrailing + pgu.getAfterBorderWidth(0, ConditionalBorder.REST);
         elementList = pgu.getElements();
-        handleExplicitHeight(
-                MinOptMaxUtil.toMinOptMax(pgu.getCell().getBlockProgressionDimension(), tableLM),
+        handleExplicitHeight(pgu.getCell().getBlockProgressionDimension().toMinOptMax(tableLM),
                 row.getExplicitHeight());
         knuthIter = elementList.listIterator();
         includedLength = -1;  // Avoid troubles with cells having content of zero length
@@ -239,7 +237,7 @@ class ActiveCell {
      * occurs. The list of elements needs to be re-adjusted after each break.
      */
     private void handleExplicitHeight(MinOptMax cellBPD, MinOptMax rowBPD) {
-        int minBPD = Math.max(cellBPD.min, rowBPD.min);
+        int minBPD = Math.max(cellBPD.getMin(), rowBPD.getMin());
         if (minBPD > 0) {
             ListIterator iter = elementList.listIterator();
             int cumulateLength = 0;
@@ -264,7 +262,7 @@ class ActiveCell {
                 }
             }
         }
-        int optBPD = Math.max(minBPD, Math.max(cellBPD.opt, rowBPD.opt));
+        int optBPD = Math.max(minBPD, Math.max(cellBPD.getOpt(), rowBPD.getOpt()));
         if (pgu.getContentLength() < optBPD) {
             elementList.add(new FillerBox(optBPD - pgu.getContentLength()));
         }
index 83e71bb216c45d4651d0c9773e3f811c2a6113d7..7c11db17d486415d617d0d6e383c4eebd61a99f3 100644 (file)
@@ -35,7 +35,6 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.ElementListObserver;
 import org.apache.fop.layoutmgr.LayoutContext;
-import org.apache.fop.layoutmgr.MinOptMaxUtil;
 import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.util.BreakUtil;
 
@@ -43,6 +42,8 @@ class RowGroupLayoutManager {
 
     private static Log log = LogFactory.getLog(RowGroupLayoutManager.class);
 
+    private static final MinOptMax MAX_STRETCH = MinOptMax.getInstance(0, 0, Integer.MAX_VALUE);
+
     private EffRow[] rowGroup;
 
     private TableLayoutManager tableLM;
@@ -146,12 +147,12 @@ class RowGroupLayoutManager {
             MinOptMax explicitRowHeight;
             TableRow tableRowFO = rowGroup[rgi].getTableRow();
             if (tableRowFO == null) {
-                rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
-                explicitRowHeight = new MinOptMax(0, 0, Integer.MAX_VALUE);
+                rowHeights[rgi] = MAX_STRETCH;
+                explicitRowHeight = MAX_STRETCH;
             } else {
                 LengthRangeProperty rowBPD = tableRowFO.getBlockProgressionDimension();
-                rowHeights[rgi] = MinOptMaxUtil.toMinOptMax(rowBPD, tableLM);
-                explicitRowHeight = MinOptMaxUtil.toMinOptMax(rowBPD, tableLM);
+                rowHeights[rgi] = rowBPD.toMinOptMax(tableLM);
+                explicitRowHeight = rowBPD.toMinOptMax(tableLM);
             }
             for (Iterator iter = row.getGridUnits().iterator(); iter.hasNext();) {
                 GridUnit gu = (GridUnit) iter.next();
@@ -168,7 +169,7 @@ class RowGroupLayoutManager {
                                 .getValue(tableLM);
                     }
                     if (gu.getRowSpanIndex() == 0) {
-                        effectiveCellBPD = Math.max(effectiveCellBPD, explicitRowHeight.opt);
+                        effectiveCellBPD = Math.max(effectiveCellBPD, explicitRowHeight.getOpt());
                     }
                     effectiveCellBPD = Math.max(effectiveCellBPD, primary.getContentLength());
                     int borderWidths = primary.getBeforeAfterBorderWidth();
@@ -179,11 +180,11 @@ class RowGroupLayoutManager {
                     padding += cbpb.getPaddingAfter(false, primary.getCellLM());
                     int effRowHeight = effectiveCellBPD + padding + borderWidths;
                     for (int prev = rgi - 1; prev >= rgi - gu.getRowSpanIndex(); prev--) {
-                        effRowHeight -= rowHeights[prev].opt;
+                        effRowHeight -= rowHeights[prev].getOpt();
                     }
-                    if (effRowHeight > rowHeights[rgi].min) {
+                    if (effRowHeight > rowHeights[rgi].getMin()) {
                         // This is the new height of the (grid) row
-                        MinOptMaxUtil.extendMinimum(rowHeights[rgi], effRowHeight);
+                        rowHeights[rgi] = rowHeights[rgi].extendMinimum(effRowHeight);
                     }
                 }
             }
index edf73acab36335c42468ce73d62a8d234be263c1..e28126c3eed290e983e3f1d84aab46e847d50814 100644 (file)
@@ -181,7 +181,7 @@ public class TableAndCaptionLayoutManager extends BlockStackingLayoutManager {
             curBlockArea = new Block();
             // Set up dimensions
             // Must get dimensions from parent area
-            Area parentArea = parentLM.getParentArea(curBlockArea);
+            Area parentArea = parentLayoutManager.getParentArea(curBlockArea);
             int referenceIPD = parentArea.getIPD();
             curBlockArea.setIPD(referenceIPD);
             // Get reference IPD from parentArea
index 9d9255e0c267581bf0a5a479f677c1907b9bf26d..c7d0d0da4cef041ab334de4df3a8de0a661520a4 100644 (file)
@@ -177,7 +177,7 @@ public class TableCaptionLayoutManager extends BlockStackingLayoutManager {
             curBlockArea = new Block();
             // Set up dimensions
             // Must get dimensions from parent area
-            Area parentArea = parentLM.getParentArea(curBlockArea);
+            Area parentArea = parentLayoutManager.getParentArea(curBlockArea);
             int referenceIPD = parentArea.getIPD();
             curBlockArea.setIPD(referenceIPD);
             // Get reference IPD from parentArea
index ea2e64afbf475d7983b7f094ab32fdfa2cd8c92d..0599b430c8d89d8d100c856170b87f406ad9e219 100644 (file)
@@ -131,7 +131,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
      * {@inheritDoc}
      */
     public List getNextKnuthElements(LayoutContext context, int alignment) {
-        MinOptMax stackLimit = new MinOptMax(context.getStackLimitBP());
+        MinOptMax stackLimit = context.getStackLimitBP();
 
         referenceIPD = context.getRefIPD();
         cellIPD = referenceIPD;
@@ -146,8 +146,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
         while ((curLM = getChildLM()) != null) {
             LayoutContext childLC = new LayoutContext(0);
             // curLM is a ?
-            childLC.setStackLimitBP(MinOptMax.subtract(context
-                    .getStackLimitBP(), stackLimit));
+            childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
             childLC.setRefIPD(cellIPD);
 
             // get elements from curLM
@@ -387,7 +386,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
                             adjustXOffset(block, dx);
                             adjustIPD(block, ipd);
                             adjustBPD(block, bpd);
-                            parentLM.addChildArea(block);
+                            parentLayoutManager.addChildArea(block);
                         }
                         dx += ipd;
                     }
@@ -439,8 +438,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
         TableColumn column = getTable().getColumn(primaryGridUnit.getColIndex());
         if (column.getCommonBorderPaddingBackground().hasBackground()) {
             Block colBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
-            ((TableLayoutManager) parentLM).registerColumnBackgroundArea(column, colBackgroundArea,
-                    -startIndent);
+            ((TableLayoutManager) parentLayoutManager).registerColumnBackgroundArea(column,
+                    colBackgroundArea, -startIndent);
         }
 
         TablePart body = primaryGridUnit.getTablePart();
@@ -452,11 +451,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
         TableRow row = primaryGridUnit.getRow();
         if (row != null && row.getCommonBorderPaddingBackground().hasBackground()) {
             Block rowBackgroundArea = getBackgroundArea(paddingRectBPD, borderBeforeWidth);
-            ((TableLayoutManager) parentLM).addBackgroundArea(rowBackgroundArea);
+            ((TableLayoutManager) parentLayoutManager).addBackgroundArea(rowBackgroundArea);
             TraitSetter.addBackground(rowBackgroundArea, row.getCommonBorderPaddingBackground(),
-                    parentLM,
+                    parentLayoutManager,
                     -xoffset - startIndent, -borderBeforeWidth,
-                    parentLM.getContentAreaIPD(), firstRowHeight);
+                    parentLayoutManager.getContentAreaIPD(), firstRowHeight);
         }
     }
 
@@ -526,7 +525,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
             curBlockArea.setYOffset(yoffset);
             curBlockArea.setIPD(cellIPD);
 
-            /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
             // Get reference IPD from parentArea
             setCurrentArea(curBlockArea); // ??? for generic operations
         }
index 9ccca8b9e24a9d496f2f78f429923fe851b49a3f..e12839b0b8a445fcb37cf36814e91754a1e79e4e 100644 (file)
@@ -327,7 +327,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager
 
         // add space before, in order to implement display-align = "center" or "after"
         if (layoutContext.getSpaceBefore() != 0) {
-            addBlockSpacing(0.0, new MinOptMax(layoutContext.getSpaceBefore()));
+            addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
         }
 
         int startXOffset = getTable().getCommonMarginBlock().startIndent.getValue(this);
@@ -404,7 +404,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager
             curBlockArea = new Block();
             // Set up dimensions
             // Must get dimensions from parent area
-            /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
+            /*Area parentArea =*/ parentLayoutManager.getParentArea(curBlockArea);
 
             TraitSetter.setProducerID(curBlockArea, getTable().getId());
 
index 92a641ed097ae9da52892db8199e50fab6a36e51..92e8ba5dd9cca8ad6afc6451abf3ba39ca676513 100644 (file)
@@ -122,7 +122,7 @@ public class TableStepper {
     private void calcTotalHeight() {
         totalHeight = 0;
         for (int i = 0; i < rowGroup.length; i++) {
-            totalHeight += rowGroup[i].getHeight().opt;
+            totalHeight += rowGroup[i].getHeight().getOpt();
         }
         if (log.isDebugEnabled()) {
             log.debug("totalHeight=" + totalHeight);
@@ -137,12 +137,12 @@ public class TableStepper {
             PrimaryGridUnit pgu = activeCell.getPrimaryGridUnit();
             for (int i = activeRowIndex + 1; i < pgu.getRowIndex() - rowGroup[0].getIndex()
                     + pgu.getCell().getNumberRowsSpanned(); i++) {
-                remain -= rowGroup[i].getHeight().opt;
+                remain -= rowGroup[i].getHeight().getOpt();
             }
             maxW = Math.max(maxW, remain);
         }
         for (int i = activeRowIndex + 1; i < rowGroup.length; i++) {
-            maxW += rowGroup[i].getHeight().opt;
+            maxW += rowGroup[i].getHeight().getOpt();
         }
         return maxW;
     }
@@ -315,7 +315,7 @@ public class TableStepper {
         if (delayingNextRow) {
             int minStep = computeMinStep();
             if (minStep < 0 || minStep >= rowFirstStep
-                    || minStep > rowGroup[activeRowIndex].getExplicitHeight().max) {
+                    || minStep > rowGroup[activeRowIndex].getExplicitHeight().getMax()) {
                 if (log.isTraceEnabled()) {
                     log.trace("Step = " + minStep);
                 }
@@ -462,7 +462,7 @@ public class TableStepper {
      */
     private void prepareNextRow() {
         if (activeRowIndex < rowGroup.length - 1) {
-            previousRowsLength += rowGroup[activeRowIndex].getHeight().opt;
+            previousRowsLength += rowGroup[activeRowIndex].getHeight().getOpt();
             activateCells(nextActiveCells, activeRowIndex + 1);
             if (log.isTraceEnabled()) {
                 log.trace("Computing first step for row " + (activeRowIndex + 2));
index a4719f896af78384ff29af6d0b78c59f83bb160d..0f0422799fd6891737f06924a49748f4e07a058b 100644 (file)
 
 package org.apache.fop.traits;
 
+import java.io.Serializable;
+
+import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.fo.properties.SpaceProperty;
+
 /**
- * This class holds the resolved (as mpoints) form of a LengthRange or
- * Space type Property value.
- * MinOptMax values are used during layout calculations. The instance
- * variables are package visible.
+ * This class holds the resolved (as mpoints) form of a {@link LengthRangeProperty LengthRange} or
+ * {@link SpaceProperty Space} type property value.
+ * <p/>
+ * Instances of this class are immutable. All arithmetic methods like {@link #plus(MinOptMax) plus},
+ * {@link #minus(MinOptMax) minus} or {@link #mult(int) mult} return a different instance. So it is
+ * possible to pass around instances without copying.
+ * <p/>
+ * <code>MinOptMax</code> values are used during layout calculations.
  */
-public class MinOptMax implements java.io.Serializable, Cloneable {
+public final class MinOptMax implements Serializable {
 
-    /** Publicly visible min(imum), opt(imum) and max(imum) values.*/
-    public int min;
-    public int opt;
-    public int max;
+    private static final long serialVersionUID = -4791524475122206142L;
 
     /**
-     * New min/opt/max with zero values.
+     * The zero <code>MinOptMax</code> instance with <code>min == opt == max == 0</code>.
      */
-    public MinOptMax() {
-        this(0);
-    }
+    public static final MinOptMax ZERO = getInstance(0);
+
+    private final int min;
+    private final int opt;
+    private final int max;
 
     /**
-     * New min/opt/max with one fixed value.
+     * Returns an instance of <code>MinOptMax</code> with the given values.
      *
-     * @param val the value for min, opt and max
+     * @param min the minimum value
+     * @param opt the optimum value
+     * @param max the maximum value
+     * @return the corresponding instance
+     * @throws IllegalArgumentException if <code>min > opt || max < opt</code>.
      */
-    public MinOptMax(int val) {
-        this(val, val, val);
+    public static MinOptMax getInstance(int min, int opt, int max) {
+        if (min > opt) {
+            throw new IllegalArgumentException("min (" + min + ") > opt (" + opt + ")");
+        }
+        if (max < opt) {
+            throw new IllegalArgumentException("max (" + max + ") < opt (" + opt + ")");
+        }
+        return new MinOptMax(min, opt, max);
     }
 
     /**
-     * New min/opt/max with the three values.
+     * Returns an instance of <code>MinOptMax</code> with one fixed value for all three
+     * properties (min, opt, max).
      *
-     * @param min the minimum value
-     * @param opt the optimum value
-     * @param max the maximum value
+     * @param value the value for min, opt and max
+     * @return the corresponding instance
+     * @see #isStiff()
      */
-    public MinOptMax(int min, int opt, int max) {
-        // TODO: assert min<=opt<=max
+    public static MinOptMax getInstance(int value) {
+        return new MinOptMax(value, value, value);
+    }
+
+    // Private constructor without consistency checks
+    private MinOptMax(int min, int opt, int max) {
+        assert min <= opt && opt <= max;
         this.min = min;
         this.opt = opt;
         this.max = max;
     }
 
     /**
-     * Copy constructor.
+     * Returns the minimum value of this <code>MinOptMax</code>.
      *
-     * @param op the MinOptMax object to copy
+     * @return the minimum value of this <code>MinOptMax</code>.
      */
-    public MinOptMax(MinOptMax op) {
-        this.min = op.min;
-        this.opt = op.opt;
-        this.max = op.max;
+    public int getMin() {
+        return min;
     }
 
-    // TODO: remove this.
     /**
-     * {@inheritDoc}
+     * Returns the optimum value of this <code>MinOptMax</code>.
+     *
+     * @return the optimum value of this <code>MinOptMax</code>.
      */
-    public Object clone() {
-        try {
-            return super.clone();
-        } catch (CloneNotSupportedException ex) {
-            // SHOULD NEVER OCCUR - all members are primitive types!
-            return null;
-        }
+    public int getOpt() {
+        return opt;
+    }
+
+    /**
+     * Returns the maximum value of this <code>MinOptMax</code>.
+     *
+     * @return the maximum value of this <code>MinOptMax</code>.
+     */
+    public int getMax() {
+        return max;
     }
 
     /**
-     * Subtracts one MinOptMax instance from another returning a new one.
-     * @param op1 first instance to subtract from
-     * @param op2 second instance
-     * @return MinOptMax new instance
+     * Returns the shrinkability of this <code>MinOptMax</code> which is the absolute difference
+     * between <code>min</code> and <code>opt</code>.
+     *
+     * @return the shrinkability of this <code>MinOptMax</code> which is always non-negative.
      */
-    public static MinOptMax subtract(MinOptMax op1, MinOptMax op2) {
-        return new MinOptMax(op1.min - op2.max, op1.opt - op2.opt,
-                             op1.max - op2.min);
+    public int getShrink() {
+        return opt - min;
     }
 
     /**
-     * Adds one MinOptMax instance to another returning a new one.
-     * @param op1 first instance
-     * @param op2 second instance
-     * @return MinOptMax new instance
+     * Returns the stretchability of this <code>MinOptMax</code> which is the absolute difference
+     * between <code>opt</code> and <code>max</code>.
+     *
+     * @return the stretchability of this <code>MinOptMax</code> which is always non-negative.
      */
-    public static MinOptMax add(MinOptMax op1, MinOptMax op2) {
-        return new MinOptMax(op1.min + op2.min, op1.opt + op2.opt,
-                             op1.max + op2.max);
+    public int getStretch() {
+        return max - opt;
     }
 
     /**
-     * Multiplies a MinOptMax instance with a factor returning a new instance.
-     * @param op1 MinOptMax instance
-     * @param mult multiplier
-     * @return MinOptMax new instance
+     * Returns the sum of this <code>MinOptMax</code> and the given <code>MinOptMax</code>.
+     *
+     * @param operand the second operand of the sum (the first is this instance itself),
+     * @return the sum of this <code>MinOptMax</code> and the given <code>MinOptMax</code>.
      */
-    public static MinOptMax multiply(MinOptMax op1, double mult) {
-        // TODO: assert mult>0
-        return new MinOptMax((int)(op1.min * mult),
-                             (int)(op1.opt * mult), (int)(op1.max * mult));
+    public MinOptMax plus(MinOptMax operand) {
+        return new MinOptMax(min + operand.min, opt + operand.opt, max + operand.max);
     }
 
+
     /**
-     * Adds another MinOptMax instance to this one.
-     * @param op the other instance
+     * Adds the given value to all three components of this instance and returns the result.
+     *
+     * @param value value to add to the min, opt, max components
+     * @return the result of the addition
      */
-    public void add(MinOptMax op) {
-        min += op.min;
-        opt += op.opt;
-        max += op.max;
+    public MinOptMax plus(int value) {
+        return new MinOptMax(min + value, opt + value, max + value);
+    }
+
+    /**
+     * Returns the difference of this <code>MinOptMax</code> and the given
+     * <code>MinOptMax</code>. This instance must be a compound of the operand and another
+     * <code>MinOptMax</code>, that is, there must exist a <code>MinOptMax</code> <i>m</i>
+     * such that <code>this.equals(m.plus(operand))</code>. In other words, the operand
+     * must have less shrink and stretch than this instance.
+     *
+     * @param operand the value to be subtracted
+     * @return the difference of this <code>MinOptMax</code> and the given
+     * <code>MinOptMax</code>.
+     * @throws ArithmeticException if this instance has strictly less shrink or stretch
+     * than the operand
+     */
+    public MinOptMax minus(MinOptMax operand) {
+        checkCompatibility(getShrink(), operand.getShrink(), "shrink");
+        checkCompatibility(getStretch(), operand.getStretch(), "stretch");
+        return new MinOptMax(min - operand.min, opt - operand.opt, max - operand.max);
+    }
+
+    private void checkCompatibility(int thisElasticity, int operandElasticity, String msge) {
+        if (thisElasticity < operandElasticity) {
+            throw new ArithmeticException(
+                    "Cannot subtract a MinOptMax from another MinOptMax that has less " + msge
+                            + " (" + thisElasticity + " < " + operandElasticity + ")");
+        }
     }
 
     /**
-     * Adds min, opt and max to their counterpart components.
-     * @param min the value to add to the minimum value
-     * @param opt the value to add to the optimum value
-     * @param max the value to add to the maximum value
+     * Subtracts the given value from all three components of this instance and returns the result.
+     *
+     * @param value value to subtract from the min, opt, max components
+     * @return the result of the subtraction
      */
-    public void add(int min, int opt, int max) {
-        this.min += min;
-        this.opt += opt;
-        this.max += max;
-        // TODO: assert min<=opt<=max
+    public MinOptMax minus(int value) {
+        return new MinOptMax(min - value, opt - value, max - value);
     }
 
     /**
-     * Adds a length to all components.
-     * @param len the length to add
+     * Returns an instance with the given value added to the minimal value.
+     *
+     * @param minOperand the minimal value to be added.
+     * @return an instance with the given value added to the minimal value.
+     * @throws IllegalArgumentException if <code>min + minOperand > opt || max < opt</code>.
+     * @deprecated Do not use! It's only for backwards compatibility.
      */
-    public void add(int len) {
-        this.min += len;
-        this.opt += len;
-        this.max += len;
+    public MinOptMax plusMin(int minOperand) {
+        return getInstance(min + minOperand, opt, max);
     }
 
+    /**
+     * Returns an instance with the given value subtracted to the minimal value.
+     *
+     * @param minOperand the minimal value to be subtracted.
+     * @return an instance with the given value subtracted to the minimal value.
+     * @throws IllegalArgumentException if <code>min - minOperand > opt || max < opt</code>.
+     * @deprecated Do not use! It's only for backwards compatibility.
+     */
+    public MinOptMax minusMin(int minOperand) {
+        return getInstance(min - minOperand, opt, max);
+    }
 
     /**
-     * Subtracts another MinOptMax instance from this one.
-     * @param op the other instance
+     * Returns an instance with the given value added to the maximal value.
+     *
+     * @param maxOperand the maximal value to be added.
+     * @return an instance with the given value added to the maximal value.
+     * @throws IllegalArgumentException if <code>min > opt || max < opt + maxOperand</code>.
+     * @deprecated Do not use! It's only for backwards compatibility.
      */
-    public void subtract(MinOptMax op) {
-        min -= op.max;
-        opt -= op.opt;
-        max -= op.min;
+    public MinOptMax plusMax(int maxOperand) {
+        return getInstance(min, opt, max + maxOperand);
     }
 
-    /** @return true if this instance represents a zero-width length (min=opt=max=0) */
+    /**
+     * Returns an instance with the given value subtracted to the maximal value.
+     *
+     * @param maxOperand the maximal value to be subtracted.
+     * @return an instance with the given value subtracted to the maximal value.
+     * @throws IllegalArgumentException if <code>min > opt || max < opt - maxOperand</code>.
+     * @deprecated Do not use! It's only for backwards compatibility.
+     */
+    public MinOptMax minusMax(int maxOperand) {
+        return getInstance(min, opt, max - maxOperand);
+    }
+
+    /**
+     * Returns the product of this <code>MinOptMax</code> and the given factor.
+     *
+     * @param factor the factor
+     * @return the product of this <code>MinOptMax</code> and the given factor
+     * @throws IllegalArgumentException if the factor is negative
+     */
+    public MinOptMax mult(int factor) {
+        if (factor < 0) {
+            throw new IllegalArgumentException("factor < 0; was: " + factor);
+        } else if (factor == 1) {
+            return this;
+        } else {
+            return getInstance(min * factor, opt * factor, max * factor);
+        }
+    }
+
+    /**
+     * Determines whether this <code>MinOptMax</code> represents a non-zero dimension, which means
+     * that not all values (min, opt, max) are zero.
+     *
+     * @return <code>true</code> if this <code>MinOptMax</code> represents a non-zero dimension;
+     *         <code>false</code> otherwise.
+     */
     public boolean isNonZero() {
-        return (min != 0 || max != 0);
+        return min != 0 || max != 0;
+    }
+
+    /**
+     * Determines whether this <code>MinOptMax</code> doesn't allow for shrinking or stretching,
+     * which means that all values (min, opt, max) are the same.
+     *
+     * @return <code>true</code> if whether this <code>MinOptMax</code> doesn't allow for shrinking
+     *         or stretching; <code>false</code> otherwise.
+     * @see #isElastic()
+     */
+    public boolean isStiff() {
+        return min == max;
     }
 
-    /** @return true if this instance allows for shrinking or stretching */
+    /**
+     * Determines whether this <code>MinOptMax</code> allows for shrinking or stretching, which
+     * means that at least one of the min or max values isn't equal to the opt value.
+     *
+     * @return <code>true</code> if this <code>MinOptMax</code> allows for shrinking or stretching;
+     *         <code>false</code> otherwise.
+     * @see #isStiff()
+     */
     public boolean isElastic() {
-        return (min != opt || opt != max);
+        return min != opt || opt != max;
     }
 
-    /** {@inheritDoc} */
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("MinOptMax[min=");
-        if (min != opt) {
-            sb.append(min).append("; ");
+    /**
+     * Extends the minimum length to the given length if necessary, and adjusts opt and max
+     * accordingly.
+     *
+     * @param newMin the new minimum length
+     * @return a <code>MinOptMax</code> instance with the minimum length extended
+     */
+    public MinOptMax extendMinimum(int newMin) {
+        if (min < newMin) {
+            int newOpt = Math.max(newMin, opt);
+            int newMax = Math.max(newOpt, max);
+            return getInstance(newMin, newOpt, newMax);
+        } else {
+            return this;
         }
-        sb.append("opt=");
-        if (opt != max) {
-            sb.append(opt).append("; ");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
         }
-        sb.append("max=").append(max);
-        sb.append("]");
-        return sb.toString();
+
+        MinOptMax minOptMax = (MinOptMax) obj;
+
+        return opt == minOptMax.opt && max == minOptMax.max && min == minOptMax.min;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int hashCode() {
+        int result = min;
+        result = 31 * result + opt;
+        result = 31 * result + max;
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        return "MinOptMax[min = " + min + ", opt = " + opt + ", max = " + max + "]";
     }
 }
 
index e2ac6fb1cc177fe86e0b3a16c65a686da95a7d2a..cb709c73e271034ea903cacf2e3f4eb20f5c2706 100644 (file)
@@ -32,9 +32,9 @@ import org.apache.fop.fonts.Font;
 public class SpaceVal {
 
     private final MinOptMax space;
-    private final boolean bConditional;
-    private final boolean bForcing;
-    private final int iPrecedence; //  Numeric only, if forcing, set to 0
+    private final boolean conditional;
+    private final boolean forcing;
+    private final int precedence; //  Numeric only, if forcing, set to 0
 
     /**
      * Constructor for SpaceVal objects based on Space objects.
@@ -42,21 +42,26 @@ public class SpaceVal {
      * @param context Percentage evaluation context
      */
     public SpaceVal(SpaceProperty spaceprop, PercentBaseContext context) {
-        space = new MinOptMax(spaceprop.getMinimum(context).getLength().getValue(context),
-                              spaceprop.getOptimum(context).getLength().getValue(context),
-                              spaceprop.getMaximum(context).getLength().getValue(context));
-        bConditional =
-                (spaceprop.getConditionality().getEnum() == Constants.EN_DISCARD);
+        space = createSpaceProperty(spaceprop, context);
+        conditional = (spaceprop.getConditionality().getEnum() == Constants.EN_DISCARD);
         Property precProp = spaceprop.getPrecedence();
         if (precProp.getNumber() != null) {
-            iPrecedence = precProp.getNumber().intValue();
-            bForcing = false;
+            precedence = precProp.getNumber().intValue();
+            forcing = false;
         } else {
-            bForcing = (precProp.getEnum() == Constants.EN_FORCE);
-            iPrecedence = 0;
+            forcing = (precProp.getEnum() == Constants.EN_FORCE);
+            precedence = 0;
         }
     }
 
+    private static MinOptMax createSpaceProperty(SpaceProperty spaceprop,
+                                                 PercentBaseContext context) {
+        int min = spaceprop.getMinimum(context).getLength().getValue(context);
+        int opt = spaceprop.getOptimum(context).getLength().getValue(context);
+        int max = spaceprop.getMaximum(context).getLength().getValue(context);
+        return MinOptMax.getInstance(min, opt, max);
+    }
+
     /**
      * Constructor for SpaceVal objects based on the full set of properties.
      * @param space space to use
@@ -64,36 +69,30 @@ public class SpaceVal {
      * @param bForcing Forcing value
      * @param iPrecedence Precedence value
      */
-    public SpaceVal(MinOptMax space, boolean bConditional,
-                    boolean bForcing, int iPrecedence) {
+    public SpaceVal(MinOptMax space, boolean conditional, boolean forcing, int precedence) {
         this.space = space;
-        this.bConditional = bConditional;
-        this.bForcing = bForcing;
-        this.iPrecedence = iPrecedence;
+        this.conditional = conditional;
+        this.forcing = forcing;
+        this.precedence = precedence;
     }
 
-    static public SpaceVal makeWordSpacing(Property wordSpacing,
-                                           SpaceVal letterSpacing,
-                                           Font fs) {
+    public static SpaceVal makeWordSpacing(Property wordSpacing, SpaceVal letterSpacing, Font fs) {
         if (wordSpacing.getEnum() == Constants.EN_NORMAL) {
             // give word spaces the possibility to shrink by a third,
             // and stretch by a half;
             int spaceCharIPD = fs.getCharWidth(' ');
-            MinOptMax space = new MinOptMax(-spaceCharIPD / 3, 0, spaceCharIPD / 2);
+            MinOptMax space = MinOptMax.getInstance(-spaceCharIPD / 3, 0, spaceCharIPD / 2);
             //TODO Adding 2 letter spaces here is not 100% correct. Spaces don't have letter spacing
-            return new SpaceVal(
-                    MinOptMax.add
-                     (space, MinOptMax.multiply(letterSpacing.getSpace(), 2)),
-                     true, true, 0);
+            return new SpaceVal(space.plus(letterSpacing.getSpace().mult(2)), true, true, 0);
         } else {
             return new SpaceVal(wordSpacing.getSpace(), null);
         }
     }
 
-    static public SpaceVal makeLetterSpacing(Property letterSpacing) {
+    public static SpaceVal makeLetterSpacing(Property letterSpacing) {
         if (letterSpacing.getEnum() == Constants.EN_NORMAL) {
             // letter spaces are set to zero (or use different values?)
-            return new SpaceVal(new MinOptMax(0), true, true, 0);
+            return new SpaceVal(MinOptMax.ZERO, true, true, 0);
         } else {
             return new SpaceVal(letterSpacing.getSpace(), null);
         }
@@ -104,7 +103,7 @@ public class SpaceVal {
      * @return the Conditionality value
      */
     public boolean isConditional() {
-        return bConditional;
+        return conditional;
     }
 
     /**
@@ -112,7 +111,7 @@ public class SpaceVal {
      * @return the Forcing value
      */
     public boolean isForcing() {
-        return bForcing;
+        return forcing;
     }
 
     /**
@@ -120,7 +119,7 @@ public class SpaceVal {
      * @return the Precedence value
      */
     public int getPrecedence() {
-        return iPrecedence;
+        return precedence;
     }
 
     /**
@@ -131,6 +130,7 @@ public class SpaceVal {
         return space;
     }
 
+    /** {@inheritDoc} */
     public String toString() {
         return "SpaceVal: " + getSpace().toString();
     }
index 250ddaad64a695c4d4d9644204204cc194b672b4..2813017899c8feaacc1bebf6083b8748b0dd8548 100644 (file)
@@ -34,6 +34,7 @@ import org.apache.fop.render.pdf.PDFCMapTestCase;
 import org.apache.fop.render.pdf.PDFEncodingTestCase;
 import org.apache.fop.render.pdf.PDFsRGBSettingsTestCase;
 import org.apache.fop.render.rtf.RichTextFormatTestSuite;
+import org.apache.fop.traits.MinOptMaxTest;
 
 /**
  * Test suite for basic functionality of FOP.
@@ -45,8 +46,7 @@ public class StandardTestSuite {
      * @return the test suite
      */
     public static Test suite() {
-        TestSuite suite = new TestSuite(
-            "Basic functionality test suite for FOP");
+        TestSuite suite = new TestSuite("Basic functionality test suite for FOP");
         //$JUnit-BEGIN$
         suite.addTest(BasicDriverTestSuite.suite());
         suite.addTest(UtilityCodeTestSuite.suite());
@@ -62,6 +62,7 @@ public class StandardTestSuite {
         suite.addTest(new TestSuite(IFMimickingTestCase.class));
         suite.addTest(new TestSuite(PageBoundariesTest.class));
         suite.addTest(new TestSuite(PageScaleTest.class));
+        suite.addTest(new TestSuite(MinOptMaxTest.class));
         //$JUnit-END$
         return suite;
     }
diff --git a/test/java/org/apache/fop/traits/MinOptMaxTest.java b/test/java/org/apache/fop/traits/MinOptMaxTest.java
new file mode 100644 (file)
index 0000000..17f46b7
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.traits;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the {@link MinOptMaxTest} class.
+ */
+public class MinOptMaxTest extends TestCase {
+
+    /**
+     * Tests that the constant <code>MinOptMax.ZERO</code> is really zero.
+     */
+    public void testZero() {
+        assertEquals(MinOptMax.getInstance(0), MinOptMax.ZERO);
+    }
+
+    public void testNewStiffMinOptMax() {
+        MinOptMax value = MinOptMax.getInstance(1);
+        assertTrue(value.isStiff());
+        assertEquals(1, value.getMin());
+        assertEquals(1, value.getOpt());
+        assertEquals(1, value.getMax());
+    }
+
+    public void testNewMinOptMax() {
+        MinOptMax value = MinOptMax.getInstance(1, 2, 3);
+        assertTrue(value.isElastic());
+        assertEquals(1, value.getMin());
+        assertEquals(2, value.getOpt());
+        assertEquals(3, value.getMax());
+    }
+
+    /**
+     * Test that it is possible to create stiff instances with the normal factory method.
+     */
+    public void testNewMinOptMaxStiff() {
+        MinOptMax value = MinOptMax.getInstance(1, 1, 1);
+        assertTrue(value.isStiff());
+        assertEquals(1, value.getMin());
+        assertEquals(1, value.getOpt());
+        assertEquals(1, value.getMax());
+    }
+
+    public void testNewMinOptMaxMinGreaterOpt() {
+        try {
+            MinOptMax.getInstance(1, 0, 2);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals("min (1) > opt (0)", e.getMessage());
+        }
+    }
+
+    public void testNewMinOptMaxMaxSmallerOpt() {
+        try {
+            MinOptMax.getInstance(0, 1, 0);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals("max (0) < opt (1)", e.getMessage());
+        }
+    }
+
+    public void testShrinkablility() {
+        assertEquals(0, MinOptMax.getInstance(1).getShrink());
+        assertEquals(1, MinOptMax.getInstance(1, 2, 2).getShrink());
+        assertEquals(2, MinOptMax.getInstance(1, 3, 3).getShrink());
+    }
+
+    public void testStrechablilty() {
+        assertEquals(0, MinOptMax.getInstance(1).getStretch());
+        assertEquals(1, MinOptMax.getInstance(1, 1, 2).getStretch());
+        assertEquals(2, MinOptMax.getInstance(1, 1, 3).getStretch());
+    }
+
+    public void testPlus() {
+        assertEquals(MinOptMax.ZERO,
+                MinOptMax.ZERO.plus(MinOptMax.ZERO));
+        assertEquals(MinOptMax.getInstance(1, 2, 3),
+                MinOptMax.ZERO.plus(MinOptMax.getInstance(1, 2, 3)));
+        assertEquals(MinOptMax.getInstance(2, 4, 6),
+                MinOptMax.getInstance(1, 2, 3).plus(MinOptMax.getInstance(1, 2, 3)));
+        assertEquals(MinOptMax.getInstance(4, 5, 6), MinOptMax.getInstance(1, 2, 3).plus(3));
+    }
+
+    public void testMinus() {
+        assertEquals(MinOptMax.ZERO,
+                MinOptMax.ZERO.minus(MinOptMax.ZERO));
+        assertEquals(MinOptMax.getInstance(1, 2, 3),
+                MinOptMax.getInstance(1, 2, 3).plus(MinOptMax.ZERO));
+        assertEquals(MinOptMax.getInstance(1, 2, 3),
+                MinOptMax.getInstance(2, 4, 6).minus(MinOptMax.getInstance(1, 2, 3)));
+        assertEquals(MinOptMax.getInstance(1, 2, 3), MinOptMax.getInstance(5, 6, 7).minus(4));
+    }
+
+    public void testMinusFail1() {
+        try {
+            MinOptMax.ZERO.minus(MinOptMax.getInstance(1, 2, 3));
+            fail();
+        } catch (ArithmeticException e) {
+            // Ok
+        }
+    }
+
+    public void testMinusFail2() {
+        try {
+            MinOptMax.getInstance(1, 2, 3).minus(MinOptMax.getInstance(1, 3, 3));
+            fail();
+        } catch (ArithmeticException e) {
+            // Ok
+        }
+    }
+
+    public void testMinusFail3() {
+        try {
+            MinOptMax.ZERO.minus(MinOptMax.getInstance(1, 1, 2));
+            fail();
+        } catch (ArithmeticException e) {
+            // Ok
+        }
+    }
+
+    public void testMinusFail4() {
+        try {
+            MinOptMax.getInstance(1, 2, 3).minus(MinOptMax.getInstance(1, 1, 3));
+            fail();
+        } catch (ArithmeticException e) {
+            // Ok
+        }
+    }
+
+    public void testMult() {
+        assertEquals(MinOptMax.ZERO, MinOptMax.ZERO.mult(0));
+        assertEquals(MinOptMax.getInstance(1, 2, 3), MinOptMax.getInstance(1, 2, 3).mult(1));
+        assertEquals(MinOptMax.getInstance(2, 4, 6), MinOptMax.getInstance(1, 2, 3).mult(2));
+    }
+
+    public void testMultFail() {
+        try {
+            MinOptMax.getInstance(1, 2, 3).mult(-1);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals("factor < 0; was: -1", e.getMessage());
+        }
+    }
+
+    public void testNonZero() {
+        assertFalse(MinOptMax.ZERO.isNonZero());
+        assertTrue(MinOptMax.getInstance(1).isNonZero());
+        assertTrue(MinOptMax.getInstance(1, 2, 3).isNonZero());
+    }
+
+    public void testExtendMinimum() {
+        assertEquals(MinOptMax.getInstance(1, 1, 1),
+                MinOptMax.ZERO.extendMinimum(1));
+        assertEquals(MinOptMax.getInstance(1, 2, 3),
+                MinOptMax.getInstance(1, 2, 3).extendMinimum(1));
+        assertEquals(MinOptMax.getInstance(2, 2, 3),
+                MinOptMax.getInstance(1, 2, 3).extendMinimum(2));
+        assertEquals(MinOptMax.getInstance(3, 3, 3),
+                MinOptMax.getInstance(1, 2, 3).extendMinimum(3));
+        assertEquals(MinOptMax.getInstance(4, 4, 4),
+                MinOptMax.getInstance(1, 2, 3).extendMinimum(4));
+    }
+
+    public void testEquals() {
+        MinOptMax number = MinOptMax.getInstance(1, 3, 5);
+        assertEquals(number, number);
+        assertEquals(number, MinOptMax.getInstance(1, 3, 5));
+        assertFalse(number.equals(MinOptMax.getInstance(2, 3, 5)));
+        assertFalse(number.equals(MinOptMax.getInstance(1, 4, 5)));
+        assertFalse(number.equals(MinOptMax.getInstance(1, 3, 4)));
+        assertFalse(number.equals(null));
+        assertFalse(number.equals(new Integer(1)));
+    }
+
+    public void testHashCode() {
+        MinOptMax number = MinOptMax.getInstance(1, 2, 3);
+        assertEquals(number.hashCode(), number.hashCode());
+        assertEquals(number.hashCode(), MinOptMax.getInstance(1, 2, 3).hashCode());
+    }
+}