Merged changes from Trunk up to revision 829121


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_Accessibility@829138 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build.xml b/build.xml
index b9b5a7b..0e0b989 100644
--- a/build.xml
+++ b/build.xml
@@ -156,10 +156,14 @@
   <property name="fo.examples.userconfig" value="conf/fop.xconf"/>
   <property name="fo.examples.include" value="**/*.fo"/>
   <property name="fo.examples.force" value="false"/>
+  <property name="xml.tests.include" value="**/*.xml"/>
+  <property name="xml.tests.force" value="false"/>
+  <property name="xml.tests.userconfig" value="conf/fop.xconf"/>
   <property name="lib.dir" value="${basedir}/lib"/>
   <property name="user.hyph.dir" value="${basedir}/hyph"/>
   <property name="unidata.dir" value="${basedir}/UNIDATA"/>
   <property name="hyph.stacksize" value="512k"/>
+  <property name="test.dir" value="${basedir}/test"/>
   <property name="build.dir" value="${basedir}/build"/>
   <property name="build.gensrc.dir" value="${build.dir}/gensrc"/>
   <property name="build.classes.dir" value="${build.dir}/classes"/>
@@ -167,9 +171,11 @@
   <property name="build.codegen-classes.dir" value="${build.dir}/codegen-classes"/>
   <property name="build.javadocs.dir" value="${build.dir}/javadocs"/>
   <property name="build.examples.dir" value="${build.dir}/examples"/>
+  <property name="build.tests.dir" value="${build.dir}/tests"/>
   <property name="build.viewer.resources.dir" value="${build.classes.dir}/org/apache/fop/render/awt/viewer/resources"/>
   <property name="build.viewer.images.dir" value="${build.classes.dir}/org/apache/fop/render/awt/viewer/images"/>
   <property name="build.property.examples.mime.type" value="application/pdf"/>
+  <property name="build.property.tests.mime.type" value="application/pdf"/>
 <!--property name="layoutengine.disabled" value="test/layoutengine/disabled-testcases.txt"/-->
 <!--property name="fotree.disabled" value="test/fotree/disabled-testcases.txt"/-->
   <property name="layoutengine.disabled" value="test/layoutengine/disabled-testcases.xml"/>
@@ -755,7 +761,7 @@
     <mkdir dir="${build.dir}/test-gensrc"/>
     <mkdir dir="${junit.reports.dir}"/>
     <javac destdir="${build.dir}/test-classes" fork="${javac.fork}" debug="${javac.debug}" deprecation="${javac.deprecation}" optimize="${javac.optimize}" source="${javac.source}" target="${javac.target}">
-      <src path="${basedir}/test/java"/>
+      <src path="${test.dir}/java"/>
       <patternset refid="test-sources"/>
       <classpath>
         <path refid="libs-build-tools-classpath"/>
@@ -765,19 +771,19 @@
       </classpath>
     </javac>
     <copy todir="${build.dir}/test-classes">
-      <fileset dir="${basedir}/test/java">
+      <fileset dir="${test.dir}/java">
         <include name="**/*.xsl"/>
       </fileset>
     </copy>
   </target>
   <target name="junit-compile-copy-resources" if="junit.present">
     <eventResourceGenerator modelfile="${build.dir}/test-gensrc/org/apache/fop/events/test-event-model.xml">
-      <fileset dir="${basedir}/test/java">
+      <fileset dir="${test.dir}/java">
         <include name="**/*.java"/>
       </fileset>
     </eventResourceGenerator>
     <copy todir="${build.dir}/test-classes">
-      <fileset dir="${basedir}/test/java">
+      <fileset dir="${test.dir}/java">
         <include name="META-INF/**"/>
         <include name="**/*.xml"/>
       </fileset>
@@ -1336,9 +1342,9 @@
     </jar>
   </target>
 <!-- =================================================================== -->
-<!-- Generate example PDFs                                               -->
+<!-- Generate examples                                                   -->
 <!-- =================================================================== -->
-  <target name="examples" depends="package" description="Generates example PDF files">
+  <target name="examples" depends="package" description="Generates the example files">
     <taskdef name="fop" classname="org.apache.fop.tools.anttasks.Fop" classpathref="libs-run-classpath"/>
     <mkdir dir="${build.examples.dir}"/>
     <fop format="${build.property.examples.mime.type}" outdir="${build.examples.dir}" messagelevel="debug" basedir="${fo.examples.dir}" userconfig="${fo.examples.userconfig}" force="${fo.examples.force}">
@@ -1347,6 +1353,20 @@
       </fileset>
     </fop>
   </target>
+
+<!-- =================================================================== -->
+<!-- Generate unit tests                                                 -->
+<!-- =================================================================== -->
+  <target name="tests" depends="package" description="Generates the test files">
+    <taskdef name="fop" classname="org.apache.fop.tools.anttasks.Fop" classpathref="libs-run-classpath"/>
+    <mkdir dir="${build.tests.dir}"/>
+    <fop format="${build.property.tests.mime.type}" xsltfile="${test.dir}/layoutengine/testcase2fo.xsl" outdir="${build.tests.dir}" messagelevel="debug" basedir="${test.dir}" userconfig="${fo.examples.userconfig}" force="${xml.tests.force}">
+      <fileset dir="${test.dir}">
+        <include name="${xml.tests.include}"/>
+      </fileset>
+    </fop>
+  </target>
+
 <!-- =================================================================== -->
 <!-- Helper task to generate source files that have already been         -->
 <!-- checked into CVS.  For these files, CVS version is the official one -->
diff --git a/lib/xmlgraphics-commons-1.4svn.jar b/lib/xmlgraphics-commons-1.4svn.jar
index 3b0a723..103e7c2 100644
--- a/lib/xmlgraphics-commons-1.4svn.jar
+++ b/lib/xmlgraphics-commons-1.4svn.jar
Binary files differ
diff --git a/src/documentation/content/xdocs/trunk/anttask.xml b/src/documentation/content/xdocs/trunk/anttask.xml
index 9dd508a..a543a56 100644
--- a/src/documentation/content/xdocs/trunk/anttask.xml
+++ b/src/documentation/content/xdocs/trunk/anttask.xml
@@ -69,6 +69,16 @@
        <td>Yes, if no fileset nested element is used</td> 
       </tr> 
       <tr> 
+       <td>xmlfile</td> 
+       <td>XML input file</td> 
+       <td>Yes, if no fofile is specified</td> 
+      </tr> 
+      <tr> 
+       <td>xsltfile</td> 
+       <td>XSLT input file</td> 
+       <td>Yes, if no fofile is specified</td> 
+      </tr> 
+      <tr> 
        <td>outfile</td> 
        <td>Output filename</td> 
        <td>Yes, when fofile is used.  (This attribute is not valid for filesets.)</td> 
@@ -196,6 +206,31 @@
    </fop>
 </target>
     ]]></source>
+    <p>
+    The following example transforms and converts a single XML and XSLT file to an AFP document:
+    </p>
+    <source><![CDATA[
+<target name="generate-afp-from-transform" description="Generates a single AFP file from an XSLT stylesheet">
+   <fop format="application/x-afp" 
+        xmlfile="c:\working\foDirectory\Document.xml"
+        xsltfile="c:\working\foDirectory\Document.xslt"
+        outfile="c:\working\afpDirectory\Document.afp" />
+</target>
+    ]]></source>
+    <p>
+    This example transforms and converts all XML files within an entire directory to PostScript:
+    </p>
+    <source><![CDATA[
+<target name="generate-multiple-ps-from-transform" description="Generates multiple PostScript files using an XSLT stylesheet">
+   <fop format="application/postscript" 
+        xsltfile="c:\working\foDirectory\Document.xslt"
+        outdir="${build.dir}" messagelevel="debug">
+        <fileset dir="${test.dir}">
+           <include name="*.xml"/>
+        </fileset>
+   </fop>
+</target>
+    ]]></source>
     </section>
     </body>
 </document>
diff --git a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java
index f6de7b5..792909b 100644
--- a/src/java/org/apache/fop/afp/AFPDataObjectFactory.java
+++ b/src/java/org/apache/fop/afp/AFPDataObjectFactory.java
@@ -24,6 +24,7 @@
 import org.apache.xmlgraphics.image.codec.tiff.TIFFImage;
 import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
 
+import org.apache.fop.afp.ioca.IDEStructureParameter;
 import org.apache.fop.afp.ioca.ImageContent;
 import org.apache.fop.afp.modca.AbstractDataObject;
 import org.apache.fop.afp.modca.AbstractNamedAFPObject;
@@ -113,12 +114,35 @@
             }
         }
 
-        if (imageObjectInfo.isColor()) {
-            imageObj.setIDESize((byte) 24);
-        } else {
-            imageObj.setIDESize((byte) imageObjectInfo.getBitsPerPixel());
+        ImageContent content = imageObj.getImageSegment().getImageContent();
+        int bitsPerPixel = imageObjectInfo.getBitsPerPixel();
+        imageObj.setIDESize((byte) bitsPerPixel);
+        IDEStructureParameter ideStruct;
+        switch (bitsPerPixel) {
+        case 1:
+            //Skip IDE Structure Parameter
+            break;
+        case 4:
+        case 8:
+            ideStruct = content.needIDEStructureParameter();
+            ideStruct.setBitsPerComponent(new int[] {bitsPerPixel});
+            break;
+        case 24:
+            ideStruct = content.needIDEStructureParameter();
+            ideStruct.setDefaultRGBColorModel();
+            break;
+        case 32:
+            ideStruct = content.needIDEStructureParameter();
+            ideStruct.setDefaultCMYKColorModel();
+            break;
+        default:
+            throw new IllegalArgumentException("Unsupported number of bits per pixel: "
+                    + bitsPerPixel);
         }
-        imageObj.setSubtractive(imageObjectInfo.isSubtractive());
+        if (imageObjectInfo.isSubtractive()) {
+            ideStruct = content.needIDEStructureParameter();
+            ideStruct.setSubtractive(imageObjectInfo.isSubtractive());
+        }
 
         imageObj.setData(imageObjectInfo.getData());
 
diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java
index 578924d..643dcb7 100644
--- a/src/java/org/apache/fop/afp/AFPPaintingState.java
+++ b/src/java/org/apache/fop/afp/AFPPaintingState.java
@@ -46,8 +46,10 @@
     /** color image support */
     private boolean colorImages = false;
 
-    /** images are supported in this AFP environment */
+    /** true if certain image formats may be embedded unchanged in their native format. */
     private boolean nativeImagesSupported = false;
+    /** true if CMYK images (requires IOCA FS45 suppport on the target platform) may be generated */
+    private boolean cmykImagesSupported;
 
     /** default value for image depth */
     private int bitsPerPixel = 8;
@@ -64,6 +66,7 @@
     /** a unit converter */
     private final transient AFPUnitConverter unitConv = new AFPUnitConverter(this);
 
+
     /**
      * Sets the rotation to be used for portrait pages, valid values are 0
      * (default), 90, 180, 270.
@@ -186,6 +189,24 @@
     }
 
     /**
+     * Controls whether CMYK images (IOCA FS45) are enabled. By default, support is disabled
+     * for wider compatibility. When disabled, any CMYK image is converted to the selected
+     * color format.
+     * @param value true to enabled CMYK images
+     */
+    public void setCMYKImagesSupported(boolean value) {
+        this.cmykImagesSupported = value;
+    }
+
+    /**
+     * Indicates whether CMYK images (IOCA FS45) are enabled.
+     * @return true if IOCA FS45 is enabled
+     */
+    public boolean isCMYKImagesSupported() {
+        return this.cmykImagesSupported;
+    }
+
+    /**
      * Sets the output/device resolution
      *
      * @param resolution
diff --git a/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java
index 4094314..6d6e44c 100644
--- a/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java
+++ b/src/java/org/apache/fop/afp/goca/GraphicsCharacterString.java
@@ -45,7 +45,7 @@
      */
     public GraphicsCharacterString(String str, int x, int y) {
         super(x, y);
-        this.str = truncate(str);
+        this.str = truncate(str, MAX_STR_LEN);
     }
 
     /**
@@ -57,7 +57,7 @@
      */
     public GraphicsCharacterString(String str) {
         super(null);
-        this.str = truncate(str);
+        this.str = truncate(str, MAX_STR_LEN);
     }
 
     /** {@inheritDoc} */
@@ -83,20 +83,6 @@
     }
 
     /**
-     * Truncates the string as necessary
-     *
-     * @param str a character string
-     * @return a possibly truncated string
-     */
-    private String truncate(String str) {
-        if (str.length() > MAX_STR_LEN) {
-            str = str.substring(0, MAX_STR_LEN);
-            log.warn("truncated character string, longer than " + MAX_STR_LEN + " chars");
-        }
-        return str;
-    }
-
-    /**
      * Returns the text string as an encoded byte array
      *
      * @return the text string as an encoded byte array
diff --git a/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java b/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java
new file mode 100644
index 0000000..8c0d0d4
--- /dev/null
+++ b/src/java/org/apache/fop/afp/ioca/IDEStructureParameter.java
@@ -0,0 +1,151 @@
+/*
+ * 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.afp.ioca;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.fop.afp.Streamable;
+
+/**
+ * This class represents the IOCA IDE Structure parameter (X'9B').
+ */
+public class IDEStructureParameter implements Streamable {
+
+    /** The RGB color model used by the IDE Structure parameter */
+    public static final byte COLOR_MODEL_RGB = (byte)0x01;
+    /** The YCrCb color model used by the IDE Structure parameter */
+    public static final byte COLOR_MODEL_YCRCB = (byte)0x02;
+    /** The CMYK color model used by the IDE Structure parameter */
+    public static final byte COLOR_MODEL_CMYK = (byte)0x04;
+    /** The YCbCr color model used by the IDE Structure parameter */
+    public static final byte COLOR_MODEL_YCBCR = (byte)0x12;
+
+    /** additive/subtractive setting for ASFLAG */
+    private boolean subtractive = false;
+
+    /** setting for GRAYCODE flag */
+    private boolean grayCoding = false;
+
+    /** the image color model */
+    private byte colorModel = COLOR_MODEL_RGB;
+
+    /** the array with the number of bits/IDE for each component */
+    private byte[] bitsPerIDE = new byte[] {(byte)1}; //1-bit by default
+
+    /**
+     * Creates a new IDE Structure parameter. The values are initialized for a bi-level image
+     * using the RGB color model.
+     */
+    public IDEStructureParameter() {
+        //nop
+    }
+
+    /**
+     * Sets the image IDE color model.
+     *
+     * @param color    the IDE color model.
+     */
+    public void setColorModel(byte color) {
+        this.colorModel = color;
+    }
+
+    /**
+     * Establishes the parameter values for the normal RGB 24bit color model.
+     */
+    public void setDefaultRGBColorModel() {
+        this.colorModel = COLOR_MODEL_RGB;
+        setUniformBitsPerComponent(3, 8);
+    }
+
+    /**
+     * Establishes the parameter values for the normal CMYK 32bit color model.
+     */
+    public void setDefaultCMYKColorModel() {
+        this.colorModel = COLOR_MODEL_CMYK;
+        setUniformBitsPerComponent(4, 8);
+    }
+
+    /**
+     * Sets
+     * @param numComponents
+     * @param bitsPerComponent
+     */
+    public void setUniformBitsPerComponent(int numComponents, int bitsPerComponent) {
+        if (bitsPerComponent < 0 || bitsPerComponent >= 256) {
+            throw new IllegalArgumentException(
+                    "The number of bits per component must be between 0 and 255");
+        }
+        this.bitsPerIDE = new byte[numComponents];
+        for (int i = 0; i < numComponents; i++) {
+            this.bitsPerIDE[i] = (byte)bitsPerComponent;
+        }
+    }
+
+    /**
+     * Sets the array for the bits/IDE, one entry per component.
+     * @param bitsPerComponent the
+     */
+    public void setBitsPerComponent(int[] bitsPerComponent) {
+        int numComponents = bitsPerComponent.length;
+        this.bitsPerIDE = new byte[numComponents];
+        for (int i = 0; i < numComponents; i++) {
+            int bits = bitsPerComponent[i];
+            if (bits < 0 || bits >= 256) {
+                throw new IllegalArgumentException(
+                        "The number of bits per component must be between 0 and 255");
+            }
+            this.bitsPerIDE[i] = (byte)bits;
+        }
+    }
+
+    /**
+     * Set either additive or subtractive mode (used for ASFLAG).
+     * @param subtractive true for subtractive mode, false for additive mode
+     */
+    public void setSubtractive(boolean subtractive) {
+        this.subtractive = subtractive;
+    }
+
+    /** {@inheritDoc} */
+    public void writeToStream(OutputStream os) throws IOException {
+        int length = 7 + bitsPerIDE.length;
+
+        byte flags = 0x00;
+        if (subtractive) {
+            flags |= 1 << 7;
+        }
+        if (grayCoding) {
+            flags |= 1 << 6;
+        }
+
+        DataOutputStream dout = new DataOutputStream(os);
+        dout.writeByte(0x9B); //ID
+        dout.writeByte(length - 2); //LENGTH
+        dout.writeByte(flags); //FLAGS
+        dout.writeByte(this.colorModel); //FORMAT
+        for (int i = 0; i < 3; i++) {
+            dout.writeByte(0); //RESERVED
+        }
+        dout.write(this.bitsPerIDE); //component sizes
+    }
+
+}
diff --git a/src/java/org/apache/fop/afp/ioca/ImageContent.java b/src/java/org/apache/fop/afp/ioca/ImageContent.java
index fe902b3..9c06589 100644
--- a/src/java/org/apache/fop/afp/ioca/ImageContent.java
+++ b/src/java/org/apache/fop/afp/ioca/ImageContent.java
@@ -56,21 +56,18 @@
     /** the image size parameter */
     private ImageSizeParameter imageSizeParameter = null;
 
+    /** the IDE Structure parameter */
+    private IDEStructureParameter ideStructureParameter = null;
+
     /** the image encoding */
     private byte encoding = (byte)0x03;
 
-    /** the image ide size */
-    private byte size = 1;
+    /** the image IDE (Image Data Element, Sample) size */
+    private byte ideSize = 1;
 
     /** the image compression */
     private byte compression = (byte)0xC0;
 
-    /** the image color model */
-    private byte colorModel = (byte)0x01;
-
-    /** additive/subtractive setting for ASFLAG */
-    private boolean subtractive = false;
-
     /** the image data */
     private byte[] data;
 
@@ -90,6 +87,34 @@
     }
 
     /**
+     * Sets the IDE Structure parameter.
+     * @param parameter the IDE Structure parameter
+     */
+    public void setIDEStructureParameter(IDEStructureParameter parameter) {
+        this.ideStructureParameter = parameter;
+    }
+
+    /**
+     * Returns the (optional) IDE Structure parameter
+     * @return the IDE Structure parameter or null if none is set
+     */
+    public IDEStructureParameter getIDEStructureParameter() {
+        return this.ideStructureParameter;
+    }
+
+    /**
+     * Returns the (optional) IDE Structure parameter. If none is set an instance is prepared
+     * with defaults for a bi-level image.
+     * @return the IDE Structure parameter
+     */
+    public IDEStructureParameter needIDEStructureParameter() {
+        if (this.ideStructureParameter == null) {
+            setIDEStructureParameter(new IDEStructureParameter());
+        }
+        return getIDEStructureParameter();
+    }
+
+    /**
      * Sets the image encoding.
      *
      * @param enc The image encoding.
@@ -113,24 +138,26 @@
      * @param s The IDE size.
      */
     public void setImageIDESize(byte s) {
-        this.size = s;
+        this.ideSize = s;
     }
 
     /**
      * Sets the image IDE color model.
      *
      * @param color    the IDE color model.
+     * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead
      */
     public void setImageIDEColorModel(byte color) {
-        this.colorModel = color;
+        needIDEStructureParameter().setColorModel(color);
     }
 
     /**
      * Set either additive or subtractive mode (used for ASFLAG).
      * @param subtractive true for subtractive mode, false for additive mode
+     * @deprecated use {@link #setIDEStructureParameter(IDEStructureParameter)} instead
      */
     public void setSubtractive(boolean subtractive) {
-        this.subtractive = subtractive;
+        needIDEStructureParameter().setSubtractive(subtractive);
     }
 
     /**
@@ -155,10 +182,12 @@
 
         os.write(getImageIDESizeParameter());
 
-        boolean useFS10 = (this.size == 1);
-        if (!useFS10) {
-            os.write(getIDEStructureParameter());
+        if (getIDEStructureParameter() != null) {
+            getIDEStructureParameter().writeToStream(os);
+        }
 
+        boolean useFS10 = (this.ideSize == 1);
+        if (!useFS10) {
             os.write(getExternalAlgorithmParameter());
         }
 
@@ -243,58 +272,15 @@
      * @return byte[] The data stream.
      */
     private byte[] getImageIDESizeParameter() {
-        if (size != 1) {
+        if (ideSize != 1) {
             final byte[] ideSizeData = new byte[] {
                     (byte)0x96, // ID
                     0x01, // Length
-                    size};
+                    ideSize};
             return ideSizeData;
         } else {
             return new byte[0];
         }
     }
 
-    /**
-     * Helper method to return the external algorithm parameter.
-     *
-     * @return byte[] The data stream.
-     */
-    private byte[] getIDEStructureParameter() {
-        byte flags = 0x00;
-        if (subtractive) {
-            flags |= 1 << 7;
-        }
-        if (colorModel != 0 && size == 24) {
-            final byte bits = (byte)(size / 3);
-            final byte[] ideStructData = new byte[] {
-                (byte)0x9B, // ID
-                0x00, // Length
-                flags, // FLAGS
-                colorModel, // COLOR MODEL
-                0x00, // Reserved
-                0x00, // Reserved
-                0x00, // Reserved
-                bits,
-                bits,
-                bits,
-            };
-            ideStructData[1] = (byte)(ideStructData.length - 2);
-            return ideStructData;
-        } else if (size == 1) {
-            final byte[] ideStructData = new byte[] {
-                    (byte)0x9B, // ID
-                    0x00, // Length
-                    flags, // FLAGS
-                    colorModel, // COLOR MODEL
-                    0x00, // Reserved
-                    0x00, // Reserved
-                    0x00, // Reserved
-                    0x01
-                };
-                ideStructData[1] = (byte)(ideStructData.length - 2);
-                return ideStructData;
-        }
-        return new byte[0];
-    }
-
 }
diff --git a/src/java/org/apache/fop/afp/ioca/ImageSegment.java b/src/java/org/apache/fop/afp/ioca/ImageSegment.java
index d8ba38e..9965bb9 100644
--- a/src/java/org/apache/fop/afp/ioca/ImageSegment.java
+++ b/src/java/org/apache/fop/afp/ioca/ImageSegment.java
@@ -56,7 +56,11 @@
         this.factory = factory;
     }
 
-    private ImageContent getImageContent() {
+    /**
+     * Returns the image content object associated with this image segment.
+     * @return the image content
+     */
+    public ImageContent getImageContent() {
         if (imageContent == null) {
             this.imageContent = factory.createImageContent();
         }
@@ -108,6 +112,7 @@
      * Sets the image IDE color model.
      *
      * @param colorModel the IDE color model.
+     * @deprecated Use {@link IDEStructureParameter#setColorModel(byte)} instead.
      */
     public void setIDEColorModel(byte colorModel) {
         getImageContent().setImageIDEColorModel(colorModel);
@@ -116,6 +121,7 @@
     /**
      * Set either additive or subtractive mode (used for ASFLAG).
      * @param subtractive true for subtractive mode, false for additive mode
+     * @deprecated Use {@link IDEStructureParameter#setSubtractive(boolean)} instead.
      */
     public void setSubtractive(boolean subtractive) {
         getImageContent().setSubtractive(subtractive);
@@ -124,7 +130,7 @@
     /**
      * Set the data image data.
      *
-     * @param data the image data
+     * @param imageData the image data
      */
     public void setData(byte[] imageData) {
         getImageContent().setImageData(imageData);
diff --git a/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java
index ae1c833..45239a6 100644
--- a/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java
+++ b/src/java/org/apache/fop/afp/modca/AbstractAFPObject.java
@@ -43,7 +43,7 @@
     /** the structured field class id */
     protected static final byte SF_CLASS = (byte)0xD3;
 
-    private static final byte[] SF_HEADER = new byte[] {
+    protected static final byte[] SF_HEADER = new byte[] {
         0x5A, // Structured field identifier
         0x00, // Length byte 1
         0x10, // Length byte 2
@@ -177,6 +177,21 @@
         }
     }
 
+    /**
+     * Truncates the string as necessary
+     *
+     * @param str a character string
+     * @param maxLength the maximum length allowed for the string
+     * @return a possibly truncated string
+     */
+    protected String truncate(String str, int maxLength) {
+        if (str.length() > maxLength) {
+            str = str.substring(0, maxLength);
+            log.warn("truncated character string '" + str + "', longer than " + maxLength + " chars");
+        }
+        return str;
+    }
+
     /** structured field type codes */
     public interface Type {
 
diff --git a/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java
index a14af29..efc38f3 100644
--- a/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java
+++ b/src/java/org/apache/fop/afp/modca/AbstractTripletStructuredObject.java
@@ -27,9 +27,12 @@
 
 import org.apache.fop.afp.modca.Registry.ObjectType;
 import org.apache.fop.afp.modca.triplets.AbstractTriplet;
+import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet;
+import org.apache.fop.afp.modca.triplets.AttributeValueTriplet;
 import org.apache.fop.afp.modca.triplets.CommentTriplet;
 import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
 import org.apache.fop.afp.modca.triplets.ObjectClassificationTriplet;
+import org.apache.fop.afp.modca.triplets.Triplet;
 
 /**
  * A MODCA structured object base class providing support for Triplets
@@ -37,7 +40,7 @@
 public class AbstractTripletStructuredObject extends AbstractStructuredObject {
 
     /** list of object triplets */
-    protected List/*<AbstractTriplet>*/ triplets = new java.util.ArrayList/*<AbstractTriplet>*/();
+    protected List/*<Triplet>*/ triplets = new java.util.ArrayList/*<Triplet>*/();
 
     /**
      * Returns the triplet data length
@@ -109,7 +112,7 @@
      *
      * @param triplet the triplet to add
      */
-    protected void addTriplet(AbstractTriplet triplet) {
+    protected void addTriplet(Triplet triplet) {
         triplets.add(triplet);
     }
 
@@ -130,7 +133,7 @@
     }
 
     /**
-     * Sets the fully qualified name of this resource
+     * Sets the fully qualified name of this structured field
      *
      * @param fqnType the fully qualified name type of this resource
      * @param fqnFormat the fully qualified name format of this resource
diff --git a/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java
index 0f99d66..38c60d7 100644
--- a/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java
+++ b/src/java/org/apache/fop/afp/modca/ContainerDataDescriptor.java
@@ -79,6 +79,8 @@
         data[18] = ysize[0];
         data[19] = ysize[1];
         data[20] = ysize[2];
+
+        os.write(data);
     }
 
 }
diff --git a/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java
index 0a7b665..386d2f4 100644
--- a/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java
+++ b/src/java/org/apache/fop/afp/modca/ImageDataDescriptor.java
@@ -31,6 +31,7 @@
 
     public static final byte FUNCTION_SET_FS10 = 0x0A;
     public static final byte FUNCTION_SET_FS11 = 0x0B;
+    public static final byte FUNCTION_SET_FS45 = 45;
 
     private byte functionSet = FUNCTION_SET_FS11; // FCNSET = IOCA FS 11
 
diff --git a/src/java/org/apache/fop/afp/modca/ImageObject.java b/src/java/org/apache/fop/afp/modca/ImageObject.java
index 65802f6..2f075ce 100644
--- a/src/java/org/apache/fop/afp/modca/ImageObject.java
+++ b/src/java/org/apache/fop/afp/modca/ImageObject.java
@@ -24,9 +24,12 @@
 
 import org.apache.commons.io.output.ByteArrayOutputStream;
 
+import org.apache.xmlgraphics.util.MimeConstants;
+
 import org.apache.fop.afp.AFPDataObjectInfo;
 import org.apache.fop.afp.AFPImageObjectInfo;
 import org.apache.fop.afp.Factory;
+import org.apache.fop.afp.ioca.IDEStructureParameter;
 import org.apache.fop.afp.ioca.ImageSegment;
 
 /**
@@ -50,7 +53,11 @@
         super(factory, name);
     }
 
-    private ImageSegment getImageSegment() {
+    /**
+     * Returns the image segment object associated with this image object.
+     * @return the image segment
+     */
+    public ImageSegment getImageSegment() {
         if (imageSegment == null) {
             this.imageSegment = factory.createImageSegment();
         }
@@ -71,6 +78,8 @@
             = factory.createImageDataDescriptor(dataWidth, dataHeight, dataWidthRes, dataHeightRes);
         if (imageObjectInfo.getBitsPerPixel() == 1) {
             imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS10);
+        } else if (MimeConstants.MIME_AFP_IOCA_FS45.equals(imageObjectInfo.getMimeType())) {
+            imageDataDescriptor.setFunctionSet(ImageDataDescriptor.FUNCTION_SET_FS45);
         }
         getObjectEnvironmentGroup().setDataDescriptor(imageDataDescriptor);
         getObjectEnvironmentGroup().setMapImageObject(
@@ -110,6 +119,7 @@
      * Sets the image IDE color model.
      *
      * @param colorModel    the IDE color model.
+     * @deprecated Use {@link IDEStructureParameter#setColorModel(byte)} instead.
      */
     public void setIDEColorModel(byte colorModel) {
         getImageSegment().setIDEColorModel(colorModel);
@@ -118,6 +128,7 @@
     /**
      * Set either additive or subtractive mode (used for ASFLAG).
      * @param subtractive true for subtractive mode, false for additive mode
+     * @deprecated Use {@link IDEStructureParameter#setSubtractive(boolean)} instead.
      */
     public void setSubtractive(boolean subtractive) {
         getImageSegment().setSubtractive(subtractive);
diff --git a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
index 5c1f7bb..cb7a67d 100644
--- a/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
+++ b/src/java/org/apache/fop/afp/modca/TagLogicalElement.java
@@ -21,9 +21,10 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
 
-import org.apache.fop.afp.AFPConstants;
+import org.apache.fop.afp.modca.triplets.AttributeQualifierTriplet;
+import org.apache.fop.afp.modca.triplets.AttributeValueTriplet;
+import org.apache.fop.afp.modca.triplets.FullyQualifiedNameTriplet;
 import org.apache.fop.afp.util.BinaryUtils;
 
 /**
@@ -45,7 +46,7 @@
  * effect on the appearance of a document when it is presented.
  * <p/>
  */
-public class TagLogicalElement extends AbstractAFPObject {
+public class TagLogicalElement extends AbstractTripletStructuredObject {
 
     /**
      * Name of the key, used within the TLE
@@ -75,77 +76,43 @@
         this.tleID = tleID;
     }
 
+    /**
+     * Sets the attribute value of this structured field
+     *
+     * @param value the attribute value
+     */
+    public void setAttributeValue(String value) {
+        addTriplet(new AttributeValueTriplet(value));
+    }
+
+    /**
+     * Sets the attribute qualifier of this structured field
+     *
+     * @param seqNumber the attribute sequence number
+     * @param levNumber the attribute level number
+     */
+    public void setAttributeQualifier(int seqNumber, int levNumber) {
+        addTriplet(new AttributeQualifierTriplet(seqNumber, levNumber));
+    }
+
     /** {@inheritDoc} */
     public void writeToStream(OutputStream os) throws IOException {
-
-        // convert name and value to ebcdic
-        byte[] tleByteName = null;
-        byte[] tleByteValue = null;
-        try {
-            tleByteName = name.getBytes(AFPConstants.EBCIDIC_ENCODING);
-            tleByteValue = value.getBytes(AFPConstants.EBCIDIC_ENCODING);
-        } catch (UnsupportedEncodingException usee) {
-            tleByteName = name.getBytes();
-            tleByteValue = value.getBytes();
-            log.warn(
-                "Constructor:: UnsupportedEncodingException translating the name "
-                + name);
-        }
-
-        byte[] data = new byte[27 + tleByteName.length + tleByteValue.length];
-
-        data[0] = 0x5A;
-        // Set the total record length
-        byte[] rl1
-            = BinaryUtils.convert(26 + tleByteName.length + tleByteValue.length, 2);
-        //Ignore first byte
-        data[1] = rl1[0];
-        data[2] = rl1[1];
-
-        // Structured field ID for a TLE
-        data[3] = (byte) 0xD3;
-        data[4] = (byte) Type.ATTRIBUTE;
-        data[5] = (byte) Category.PROCESS_ELEMENT;
-
-        data[6] = 0x00; // Reserved
-        data[7] = 0x00; // Reserved
-        data[8] = 0x00; // Reserved
-
-        //Use 2 triplets, attribute name and value (the key for indexing)
-
-        byte[] rl2 = BinaryUtils.convert(tleByteName.length + 4, 1);
-        data[9] = rl2[0]; // length of the triplet, including this field
-        data[10] = 0x02; //Identifies it as a FQN triplet
-        data[11] = 0x0B; // GID format
-        data[12] = 0x00;
-
-        // write out TLE name
-        int pos = 13;
-        for (int i = 0; i < tleByteName.length; i++) {
-            data[pos++] = tleByteName[i];
-        }
-
-        byte[] rl3 = BinaryUtils.convert(tleByteValue.length + 4, 1);
-        data[pos++] = rl3[0]; // length of the triplet, including this field
-        data[pos++] = 0x36; //Identifies the triplet, attribute value
-        data[pos++] = 0x00; // Reserved
-        data[pos++] = 0x00; // Reserved
-
-        for (int i = 0; i < tleByteValue.length; i++) {
-            data[pos++] = tleByteValue[i];
-        }
-        // attribute qualifier
-        data[pos++] = 0x0A;
-        data[pos++] = (byte)0x80;
-        byte[] id = BinaryUtils.convert(tleID, 4);
-        for (int i = 0; i < id.length; i++) {
-            data[pos++] = id[i];
-        }
-        byte[] level = BinaryUtils.convert(1, 4);
-        for (int i = 0; i < level.length; i++) {
-            data[pos++] = level[i];
-        }
-
+        setFullyQualifiedName(
+                FullyQualifiedNameTriplet.TYPE_ATTRIBUTE_GID,
+                FullyQualifiedNameTriplet.FORMAT_CHARSTR,
+                name);
+        setAttributeQualifier(tleID, 1);
+        setAttributeValue(value);
+        
+        byte[] data = new byte[SF_HEADER.length];
+        copySF(data, Type.ATTRIBUTE, Category.PROCESS_ELEMENT);
+        
+        int tripletDataLength = getTripletDataLength();
+        byte[] l = BinaryUtils.convert(data.length + tripletDataLength - 1, 2);
+        data[1] = l[0];
+        data[2] = l[1];
         os.write(data);
+
+        writeTriplets(os);
     }
 }
diff --git a/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java
index 598df1b..5cd136a 100644
--- a/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java
+++ b/src/java/org/apache/fop/afp/modca/triplets/AbstractTriplet.java
@@ -19,70 +19,12 @@
 
 package org.apache.fop.afp.modca.triplets;
 
-import org.apache.fop.afp.Streamable;
-import org.apache.fop.afp.StructuredData;
+import org.apache.fop.afp.modca.AbstractAFPObject;
 
 /**
  * A simple implementation of a MOD:CA triplet
  */
-public abstract class AbstractTriplet implements Streamable, StructuredData {
-    public static final byte CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER = 0x01;
-
-    /** Triplet identifiers */
-    public static final byte FULLY_QUALIFIED_NAME = 0x02;
-    public static final byte MAPPING_OPTION = 0x04;
-    public static final byte OBJECT_CLASSIFICATION = 0x10;
-    public static final byte MODCA_INTERCHANGE_SET = 0x18;
-    public static final byte FONT_DESCRIPTOR_SPECIFICATION = 0x1F;
-    public static final byte OBJECT_FUNCTION_SET_SPECIFICATION = 0x21;
-    public static final byte EXTENDED_RESOURCE_LOCAL_IDENTIFIER = 0x22;
-    public static final byte RESOURCE_LOCAL_IDENTIFIER = 0x24;
-    public static final byte RESOURCE_SECTION_NUMBER = 0x25;
-    public static final byte CHARACTER_ROTATION = 0x26;
-    public static final byte OBJECT_BYTE_OFFSET = 0x2D;
-    public static final byte ATTRIBUTE_VALUE = 0x36;
-    public static final byte DESCRIPTOR_POSITION = 0x43;
-    public static final byte MEDIA_EJECT_CONTROL = 0x45;
-    public static final byte PAGE_OVERLAY_CONDITIONAL_PROCESSING = 0x46;
-    public static final byte RESOURCE_USAGE_ATTRIBUTE = 0x47;
-    public static final byte MEASUREMENT_UNITS = 0x4B;
-    public static final byte OBJECT_AREA_SIZE = 0x4C;
-    public static final byte AREA_DEFINITION = 0x4D;
-    public static final byte COLOR_SPECIFICATION = 0x4E;
-    public static final byte ENCODING_SCHEME_ID = 0x50;
-    public static final byte MEDIUM_MAP_PAGE_NUMBER = 0x56;
-    public static final byte OBJECT_BYTE_EXTENT = 0x57;
-    public static final byte OBJECT_STRUCTURED_FIELD_OFFSET = 0x58;
-    public static final byte OBJECT_STRUCTURED_FIELD_EXTENT = 0x59;
-    public static final byte OBJECT_OFFSET = 0x5A;
-    public static final byte FONT_HORIZONTAL_SCALE_FACTOR = 0x5D;
-    public static final byte OBJECT_COUNT = 0x5E;
-    public static final byte OBJECT_DATE_AND_TIMESTAMP = 0x62;
-    public static final byte COMMENT = 0x65;
-    public static final byte MEDIUM_ORIENTATION = 0x68;
-    public static final byte RESOURCE_OBJECT_INCLUDE = 0x6C;
-    public static final byte PRESENTATION_SPACE_RESET_MIXING = 0x70;
-    public static final byte PRESENTATION_SPACE_MIXING_RULE = 0x71;
-    public static final byte UNIVERSAL_DATE_AND_TIMESTAMP = 0x72;
-    public static final byte TONER_SAVER = 0x74;
-    public static final byte COLOR_FIDELITY = 0x75;
-    public static final byte FONT_FIDELITY = 0x78;
-    public static final byte ATTRIBUTE_QUALIFIER = (byte)0x80;
-    public static final byte PAGE_POSITION_INFORMATION = (byte)0x81;
-    public static final byte PARAMETER_VALUE = (byte)0x82;
-    public static final byte PRESENTATION_CONTROL = (byte)0x83;
-    public static final byte FONT_RESOLUTION_AND_METRIC_TECHNOLOGY = (byte)0x84;
-    public static final byte FINISHING_OPERATION = (byte)0x85;
-    public static final byte TEXT_FIDELITY = (byte)0x86;
-    public static final byte MEDIA_FIDELITY = (byte)0x87;
-    public static final byte FINISHING_FIDELITY = (byte)0x88;
-    public static final byte DATA_OBJECT_FONT_DESCRIPTOR = (byte)0x8B;
-    public static final byte LOCALE_SELECTOR = (byte)0x8C;
-    public static final byte UP3I_FINISHING_OPERATION = (byte)0x8E;
-    public static final byte COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR = (byte)0x91;
-    public static final byte RENDERING_INTENT = (byte)0x95;
-    public static final byte CMR_TAG_FIDELITY = (byte)0x96;
-    public static final byte DEVICE_APPEARANCE = (byte)0x97;
+public abstract class AbstractTriplet extends AbstractAFPObject implements Triplet {
 
     /** the triplet identifier */
     protected final byte id;
diff --git a/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java
new file mode 100644
index 0000000..2f924d5
--- /dev/null
+++ b/src/java/org/apache/fop/afp/modca/triplets/AttributeQualifierTriplet.java
@@ -0,0 +1,67 @@
+/*
+ * 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.afp.modca.triplets;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.fop.afp.util.BinaryUtils;
+
+/**
+ * The attribute qualifier triplet is used to specify a qualifier for a document
+ * attribute.
+ */
+public class AttributeQualifierTriplet extends AbstractTriplet {
+
+    private int seqNumber;
+    private int levNumber;
+
+    /**
+     * Main constructor
+     *
+     * @param seqNumber the attribute qualifier sequence number
+     * @param levNumber the attribute qualifier level number
+     */
+    public AttributeQualifierTriplet(int seqNumber, int levNumber) {
+        super(ATTRIBUTE_QUALIFIER);
+        this.seqNumber = seqNumber;
+        this.levNumber = levNumber;
+    }
+
+    /** {@inheritDoc} */
+    public void writeToStream(OutputStream os) throws IOException {
+        byte[] data = getData();
+        byte[] id = BinaryUtils.convert(seqNumber, 4);
+        System.arraycopy(id, 0, data, 2, id.length);
+        byte[] level = BinaryUtils.convert(levNumber, 4);
+        System.arraycopy(level, 0, data, 6, level.length);
+        os.write(data);
+    }
+
+    /** {@inheritDoc} */
+    public int getDataLength() {
+        return 10;
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return "seqNumber=" + seqNumber + ", levNumber=" + levNumber;
+    }
+}
diff --git a/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java b/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java
new file mode 100644
index 0000000..ec2ae8d
--- /dev/null
+++ b/src/java/org/apache/fop/afp/modca/triplets/AttributeValueTriplet.java
@@ -0,0 +1,72 @@
+/*
+ * 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.afp.modca.triplets;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.fop.afp.AFPConstants;
+
+/**
+ * The attribute value triplet is used to specify a value for a document
+ * attribute.
+ */
+public class AttributeValueTriplet extends AbstractTriplet {
+    private String attVal;
+
+    /**
+     * Main constructor
+     *
+     * @param attVal an attribute value
+     */
+    public AttributeValueTriplet(String attVal) {
+        super(ATTRIBUTE_VALUE);
+        this.attVal = truncate(attVal, MAX_LENGTH - 4);
+    }
+
+    /** {@inheritDoc} */
+    public void writeToStream(OutputStream os) throws IOException {
+        byte[] data = super.getData();
+        data[2] = 0x00; // Reserved
+        data[3] = 0x00; // Reserved
+
+        // convert name and value to ebcdic
+        byte[] tleByteValue = null;
+        try {
+            tleByteValue = attVal.getBytes(AFPConstants.EBCIDIC_ENCODING);
+        } catch (UnsupportedEncodingException usee) {
+            tleByteValue = attVal.getBytes();
+            throw new IllegalArgumentException(attVal + " encoding failed");
+        }
+        System.arraycopy(tleByteValue, 0, data, 4, tleByteValue.length);
+        os.write(data);
+    }
+
+    /** {@inheritDoc} */
+    public int getDataLength() {
+        return 4 + attVal.length();
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return attVal;
+    }
+}
diff --git a/src/java/org/apache/fop/afp/modca/triplets/Triplet.java b/src/java/org/apache/fop/afp/modca/triplets/Triplet.java
new file mode 100644
index 0000000..726727e
--- /dev/null
+++ b/src/java/org/apache/fop/afp/modca/triplets/Triplet.java
@@ -0,0 +1,85 @@
+/*
+ * 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.afp.modca.triplets;
+
+import org.apache.fop.afp.Streamable;
+import org.apache.fop.afp.StructuredData;
+
+public interface Triplet extends Streamable, StructuredData {
+    int MAX_LENGTH = 254;
+
+    byte CODED_GRAPHIC_CHARACTER_SET_GLOBAL_IDENTIFIER = 0x01;
+
+    /** Triplet identifiers */
+    byte FULLY_QUALIFIED_NAME = 0x02;
+    byte MAPPING_OPTION = 0x04;
+    byte OBJECT_CLASSIFICATION = 0x10;
+    byte MODCA_INTERCHANGE_SET = 0x18;
+    byte FONT_DESCRIPTOR_SPECIFICATION = 0x1F;
+    byte OBJECT_FUNCTION_SET_SPECIFICATION = 0x21;
+    byte EXTENDED_RESOURCE_LOCAL_IDENTIFIER = 0x22;
+    byte RESOURCE_LOCAL_IDENTIFIER = 0x24;
+    byte RESOURCE_SECTION_NUMBER = 0x25;
+    byte CHARACTER_ROTATION = 0x26;
+    byte OBJECT_BYTE_OFFSET = 0x2D;
+    byte ATTRIBUTE_VALUE = 0x36;
+    byte DESCRIPTOR_POSITION = 0x43;
+    byte MEDIA_EJECT_CONTROL = 0x45;
+    byte PAGE_OVERLAY_CONDITIONAL_PROCESSING = 0x46;
+    byte RESOURCE_USAGE_ATTRIBUTE = 0x47;
+    byte MEASUREMENT_UNITS = 0x4B;
+    byte OBJECT_AREA_SIZE = 0x4C;
+    byte AREA_DEFINITION = 0x4D;
+    byte COLOR_SPECIFICATION = 0x4E;
+    byte ENCODING_SCHEME_ID = 0x50;
+    byte MEDIUM_MAP_PAGE_NUMBER = 0x56;
+    byte OBJECT_BYTE_EXTENT = 0x57;
+    byte OBJECT_STRUCTURED_FIELD_OFFSET = 0x58;
+    byte OBJECT_STRUCTURED_FIELD_EXTENT = 0x59;
+    byte OBJECT_OFFSET = 0x5A;
+    byte FONT_HORIZONTAL_SCALE_FACTOR = 0x5D;
+    byte OBJECT_COUNT = 0x5E;
+    byte OBJECT_DATE_AND_TIMESTAMP = 0x62;
+    byte COMMENT = 0x65;
+    byte MEDIUM_ORIENTATION = 0x68;
+    byte RESOURCE_OBJECT_INCLUDE = 0x6C;
+    byte PRESENTATION_SPACE_RESET_MIXING = 0x70;
+    byte PRESENTATION_SPACE_MIXING_RULE = 0x71;
+    byte UNIVERSAL_DATE_AND_TIMESTAMP = 0x72;
+    byte TONER_SAVER = 0x74;
+    byte COLOR_FIDELITY = 0x75;
+    byte FONT_FIDELITY = 0x78;
+    byte ATTRIBUTE_QUALIFIER = (byte)0x80;
+    byte PAGE_POSITION_INFORMATION = (byte)0x81;
+    byte PARAMETER_VALUE = (byte)0x82;
+    byte PRESENTATION_CONTROL = (byte)0x83;
+    byte FONT_RESOLUTION_AND_METRIC_TECHNOLOGY = (byte)0x84;
+    byte FINISHING_OPERATION = (byte)0x85;
+    byte TEXT_FIDELITY = (byte)0x86;
+    byte MEDIA_FIDELITY = (byte)0x87;
+    byte FINISHING_FIDELITY = (byte)0x88;
+    byte DATA_OBJECT_FONT_DESCRIPTOR = (byte)0x8B;
+    byte LOCALE_SELECTOR = (byte)0x8C;
+    byte UP3I_FINISHING_OPERATION = (byte)0x8E;
+    byte COLOR_MANAGEMENT_RESOURCE_DESCRIPTOR = (byte)0x91;
+    byte RENDERING_INTENT = (byte)0x95;
+    byte CMR_TAG_FIDELITY = (byte)0x96;
+    byte DEVICE_APPEARANCE = (byte)0x97;
+}
diff --git a/src/java/org/apache/fop/cli/CommandLineOptions.java b/src/java/org/apache/fop/cli/CommandLineOptions.java
index 043dfe3..2e6e204 100644
--- a/src/java/org/apache/fop/cli/CommandLineOptions.java
+++ b/src/java/org/apache/fop/cli/CommandLineOptions.java
@@ -109,6 +109,8 @@
     private boolean useStdIn = false;
     /* true if System.out (stdout) should be used for the output file */
     private boolean useStdOut = false;
+    /* true if a catalog resolver should be used for entity and uri resolution */ 
+    private boolean useCatalogResolver = false;
     /* rendering options (for the user agent) */
     private Map renderingOptions = new java.util.HashMap();
     /* target resolution (for the user agent) */
@@ -354,6 +356,8 @@
                   } else {
                       throw new FOPException("invalid param usage: use -param <name> <value>");
                   }
+            } else if (args[i].equals("-catalog")) {
+                useCatalogResolver = true;
             } else if (args[i].equals("-o")) {
                 i = i + parsePDFOwnerPassword(args, i);
             } else if (args[i].equals("-u")) {
@@ -1024,7 +1028,7 @@
             case IF_INPUT:
                 return new IFInputHandler(iffile);
             case XSLT_INPUT:
-                return new InputHandler(xmlfile, xsltfile, xsltParams);
+                return new InputHandler(xmlfile, xsltfile, xsltParams, useCatalogResolver);
             case IMAGE_INPUT:
                 return new ImageInputHandler(imagefile, xsltfile, xsltParams);
             default:
@@ -1166,6 +1170,7 @@
             + "  -xsl stylesheet   xslt stylesheet \n \n"
             + "  -param name value <value> to use for parameter <name> in xslt stylesheet\n"
             + "                    (repeat '-param name value' for each parameter)\n \n"
+            + "  -catalog          use catalog resolver for input XML and XSLT files\n"
             + " [OUTPUT] \n"
             + "  outfile           input will be rendered as PDF into outfile\n"
             + "                    (use '-' for outfile to pipe output to stdout)\n"
diff --git a/src/java/org/apache/fop/cli/InputHandler.java b/src/java/org/apache/fop/cli/InputHandler.java
index 4f49ea2..a1ff171 100644
--- a/src/java/org/apache/fop/cli/InputHandler.java
+++ b/src/java/org/apache/fop/cli/InputHandler.java
@@ -19,7 +19,6 @@
 
 package org.apache.fop.cli;
 
-// Imported java.io classes
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
@@ -34,11 +33,13 @@
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 
+import org.xml.sax.EntityResolver;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
@@ -51,27 +52,27 @@
 import org.apache.fop.apps.Fop;
 import org.apache.fop.apps.FopFactory;
 import org.apache.fop.render.awt.viewer.Renderable;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
 
 /**
  * Class for handling files input from command line
  * either with XML and XSLT files (and optionally xsl
- * parameters) or FO File input alone
+ * parameters) or FO File input alone.
  */
 public class InputHandler implements ErrorListener, Renderable {
 
     /** original source file */
-    protected File sourcefile = null;
-    private File stylesheet = null;  // for XML/XSLT usage
-    private Vector xsltParams = null; // for XML/XSLT usage
+    protected File sourcefile;
+    private File stylesheet;  // for XML/XSLT usage
+    private Vector xsltParams; // for XML/XSLT usage
+    private EntityResolver entityResolver;
+    private URIResolver uriResolver;
 
     /** the logger */
     protected Log log = LogFactory.getLog(InputHandler.class);
 
     /**
      * Constructor for XML->XSLT->FO input
+     *
      * @param xmlfile XML file
      * @param xsltfile XSLT file
      * @param params Vector of command-line parameters (name, value,
@@ -84,6 +85,23 @@
     }
 
     /**
+     * Constructor for XML->XSLT->FO input
+     *
+     * @param xmlfile XML file
+     * @param xsltfile XSLT file
+     * @param params Vector of command-line parameters (name, value,
+     *      name, value, ...) for XSL stylesheet, null if none
+     * @param useCatalogResolver if true, use a catalog resolver
+     *      for XML parsing and XSLT URI resolution
+     */
+    public InputHandler(File xmlfile, File xsltfile, Vector params, boolean useCatalogResolver) {
+        this(xmlfile, xsltfile, params);
+        if (useCatalogResolver) {
+            createCatalogResolver();
+        }
+    }
+
+    /**
      * Constructor for FO input
      * @param fofile the file to read the FO document.
      */
@@ -151,7 +169,7 @@
      * @return the Source for the main input file
      */
     protected Source createMainSource() {
-        Source result;
+        Source source;
         InputStream in;
         String uri;
         if (this.sourcefile != null) {
@@ -169,37 +187,91 @@
         try {
             InputSource is = new InputSource(in);
             is.setSystemId(uri);
-            SAXParserFactory spf = SAXParserFactory.newInstance();
-            spf.setFeature("http://xml.org/sax/features/namespaces", true);
-            spf.setFeature("http://apache.org/xml/features/xinclude", true);
-            XMLReader xr = spf.newSAXParser().getXMLReader();
-            result = new SAXSource(xr, is);
+            XMLReader xr = getXMLReader();
+            if (entityResolver != null) {
+                xr.setEntityResolver(entityResolver);
+            }
+            source = new SAXSource(xr, is);
         } catch (SAXException e) {
             if (this.sourcefile != null) {
-                result = new StreamSource(this.sourcefile);
+                source = new StreamSource(this.sourcefile);
             } else {
-                result = new StreamSource(in, uri);
+                source = new StreamSource(in, uri);
             }
         } catch (ParserConfigurationException e) {
             if (this.sourcefile != null) {
-                result = new StreamSource(this.sourcefile);
+                source = new StreamSource(this.sourcefile);
             } else {
-                result = new StreamSource(in, uri);
+                source = new StreamSource(in, uri);
             }
         }
-        return result;
+        return source;
+    }
+
+    /**
+     * Creates a catalog resolver and uses it for XML parsing and XSLT URI resolution.
+     * Tries the Apache Commons Resolver, and if unsuccessful,
+     * tries the same built into Java 6.
+     */
+    private void createCatalogResolver() {
+        String[] classNames = new String[] {
+                "org.apache.xml.resolver.tools.CatalogResolver",
+                "com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver"};
+        Class resolverClass = null;
+        for (int i = 0; i < classNames.length && resolverClass == null; ++i) {
+            try {
+                resolverClass = Class.forName(classNames[i]);
+            } catch (ClassNotFoundException e) {
+                // No worries
+            }
+        }
+        if (resolverClass == null) {
+            log.error("Could not find catalog resolver in class path");
+            return;
+        }
+        try {
+            entityResolver = (EntityResolver) resolverClass.newInstance();
+            uriResolver = (URIResolver) resolverClass.newInstance();
+        } catch (InstantiationException e) {
+            log.error("Error creating the catalog resolver: " + e.getMessage());
+        } catch (IllegalAccessException e) {
+            log.error("Error creating the catalog resolver: " + e.getMessage());
+        }
     }
 
     /**
      * Creates a Source for the selected stylesheet.
+     *
      * @return the Source for the selected stylesheet or null if there's no stylesheet
      */
     protected Source createXSLTSource() {
+        Source xslt = null;
         if (this.stylesheet != null) {
-            return new StreamSource(this.stylesheet);
-        } else {
-            return null;
+            if (entityResolver != null) {
+                try {
+                    InputSource is = new InputSource(this.stylesheet.getPath());
+                    XMLReader xr = getXMLReader();
+                    xr.setEntityResolver(entityResolver);
+                    xslt = new SAXSource(xr, is);
+                } catch (SAXException e) {
+                    // return StreamSource
+                } catch (ParserConfigurationException e) {
+                    // return StreamSource
+                }
+            }
+            if (xslt == null) {
+                xslt = new StreamSource(this.stylesheet);
+            }
         }
+        return xslt;
+    }
+
+    private XMLReader getXMLReader() throws ParserConfigurationException, SAXException {
+        SAXParserFactory spf = SAXParserFactory.newInstance();
+        spf.setFeature("http://xml.org/sax/features/namespaces", true);
+        spf.setFeature("http://apache.org/xml/features/xinclude", true);
+        XMLReader xr = spf.newSAXParser().getXMLReader();
+        return xr;
     }
 
     /**
@@ -226,6 +298,9 @@
                             (String) xsltParams.elementAt(i + 1));
                     }
                 }
+                if (uriResolver != null) {
+                    transformer.setURIResolver(uriResolver);
+                }
             }
             transformer.setErrorListener(this);
 
diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java
index 2ebfaaf..133d932 100644
--- a/src/java/org/apache/fop/fo/FObj.java
+++ b/src/java/org/apache/fop/fo/FObj.java
@@ -56,7 +56,7 @@
     private List/*<ExtensionAttachment>*/ extensionAttachments = null;
 
     /** The map of foreign attributes, null if none */
-    private Map foreignAttributes = null;
+    private Map/*<QName,String>*/ foreignAttributes = null;
 
     /** Used to indicate if this FO is either an Out Of Line FO (see rec)
      *  or a descendant of one. Used during FO validation.
@@ -591,7 +591,7 @@
             throw new NullPointerException("Parameter attributeName must not be null");
         }
         if (foreignAttributes == null) {
-            foreignAttributes = new java.util.HashMap();
+            foreignAttributes = new java.util.HashMap/*<QName,String>*/();
         }
         foreignAttributes.put(attributeName, value);
     }
diff --git a/src/java/org/apache/fop/fonts/CIDSubset.java b/src/java/org/apache/fop/fonts/CIDSubset.java
index c250548..6be4007 100644
--- a/src/java/org/apache/fop/fonts/CIDSubset.java
+++ b/src/java/org/apache/fop/fonts/CIDSubset.java
@@ -161,12 +161,12 @@
     }
 
     /**
-     * Returns a BitSet with bits set for each available glyph index.
+     * Returns a BitSet with bits set for each available glyph index in the subset.
      * @return a BitSet indicating available glyph indices
      */
     public BitSet getGlyphIndexBitSet() {
         BitSet bitset = new BitSet();
-        Iterator iter = usedGlyphs.keySet().iterator();
+        Iterator iter = usedGlyphsIndex.keySet().iterator();
         while (iter.hasNext()) {
             Integer cid = (Integer)iter.next();
             bitset.set(cid.intValue());
diff --git a/src/java/org/apache/fop/fonts/Font.java b/src/java/org/apache/fop/fonts/Font.java
index e9740c0..d0a87ef 100644
--- a/src/java/org/apache/fop/fonts/Font.java
+++ b/src/java/org/apache/fop/fonts/Font.java
@@ -170,6 +170,9 @@
 
     /**
      * Returns the amount of kerning between two characters.
+     *
+     * The value returned measures in pt. So it is already adjusted for font size.
+     *
      * @param ch1 first character
      * @param ch2 second character
      * @return the distance to adjust for kerning, 0 if there's no kerning
@@ -179,7 +182,7 @@
         if (kernPair != null) {
             Integer width = (Integer)kernPair.get(new Integer(ch2));
             if (width != null) {
-                return width.intValue();
+                return width.intValue() * getFontSize() / 1000;
             }
         }
         return 0;
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index 1a6f7cf..53a5259 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -367,7 +367,7 @@
                 alg.setConstantLineWidth(flowBPD);
                 int optimalPageCount = alg.findBreakingPoints(effectiveList, 1, true,
                         BreakingAlgorithm.ALL_BREAKS);
-                if (alg.ipdChanged()) {
+                if (alg.getIPDdifference() != 0) {
                     KnuthNode optimalBreak = alg.getBestNodeBeforeIPDChange();
                     int positionIndex = optimalBreak.position;
                     KnuthElement elementAtBreak = alg.getElement(positionIndex);
@@ -381,14 +381,19 @@
                     LayoutManager restartAtLM = null;
                     List firstElements = Collections.EMPTY_LIST;
                     if (containsNonRestartableLM(positionAtBreak)) {
+                        if (alg.getIPDdifference() > 0) {
+                            log.warn("Content that cannot handle IPD changes is flowing to a"
+                                    + " narrower page. Part of it may be clipped"
+                                    + " by the page border.");
+                        }
                         firstElements = new LinkedList();
                         boolean boxFound = false;
-                        Iterator iter = effectiveList.listIterator(++positionIndex);
+                        Iterator iter = effectiveList.listIterator(positionIndex + 1);
                         Position position = null;
                         while (iter.hasNext()
                                 && (position == null || containsNonRestartableLM(position))) {
-                            KnuthElement element = (KnuthElement) iter.next();
                             positionIndex++;
+                            KnuthElement element = (KnuthElement) iter.next();
                             position = element.getPosition();
                             if (element.isBox()) {
                                 boxFound = true;
@@ -400,9 +405,11 @@
                         if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) {
                             /* Retrieve the original position wrapped into this space position */
                             positionAtBreak = position.getPosition();
+                        } else {
+                            positionAtBreak = null;
                         }
                     }
-                    if (positionAtBreak.getIndex() == -1) {
+                    if (positionAtBreak != null && positionAtBreak.getIndex() == -1) {
                         /*
                          * This is an indication that we are between two blocks
                          * (possibly surrounded by another block), not inside a
@@ -588,7 +595,7 @@
                             .listIterator(startElementIndex);
                     while (effectiveListIterator.nextIndex() <= endElementIndex) {
                         KnuthElement tempEl = (KnuthElement)effectiveListIterator.next();
-                        if (tempEl.isBox() && tempEl.getW() > 0) {
+                        if (tempEl.isBox() && tempEl.getWidth() > 0) {
                             boxCount++;
                         }
                     }
@@ -678,8 +685,23 @@
 
         BlockSequence blockList;
         List returnedList;
-        if (positionAtIPDChange == null) {
+        if (firstElements == null) {
             returnedList = getNextKnuthElements(childLC, alignment);
+        } else if (positionAtIPDChange == null) {
+            /*
+             * No restartable element found after changing IPD break. Simply add the
+             * non-restartable elements found after the break.
+             */
+            returnedList = firstElements;
+            /*
+             * Remove the last 3 penalty-filler-forced break elements that were added by
+             * the Knuth algorithm. They will be re-added later on.
+             */
+            ListIterator iter = returnedList.listIterator(returnedList.size());
+            for (int i = 0; i < 3; i++) {
+                iter.previous();
+                iter.remove();
+            }
         } else {
             returnedList = getNextKnuthElements(childLC, alignment, positionAtIPDChange,
                     restartAtLM);
@@ -861,9 +883,9 @@
                     case BlockLevelLayoutManager.LINE_NUMBER_ADJUSTMENT:
                         // potential line number adjustment
                         lineNumberMaxAdjustment.max += ((KnuthGlue) thisElement)
-                                .getY();
+                                .getStretch();
                         lineNumberMaxAdjustment.min -= ((KnuthGlue) thisElement)
-                                .getZ();
+                                .getShrink();
                         adjustableLinesList.add(thisElement);
                         break;
                     case BlockLevelLayoutManager.LINE_HEIGHT_ADJUSTMENT:
@@ -885,9 +907,9 @@
                             KnuthGlue blockSpace = (KnuthGlue) unconfirmedList
                                     .removeFirst();
                             spaceMaxAdjustment.max += ((KnuthGlue) blockSpace)
-                                    .getY();
+                                    .getStretch();
                             spaceMaxAdjustment.min -= ((KnuthGlue) blockSpace)
-                                    .getZ();
+                                    .getShrink();
                             blockSpacesList.add(blockSpace);
                         }
                     }
@@ -898,11 +920,11 @@
             log.debug("| space adj      = "
                     + spaceMaxAdjustment);
 
-            if (thisElement.isPenalty() && thisElement.getW() > 0) {
+            if (thisElement.isPenalty() && thisElement.getWidth() > 0) {
                 log.debug("  mandatory variation to the number of lines!");
                 ((BlockLevelLayoutManager) thisElement
                         .getLayoutManager()).negotiateBPDAdjustment(
-                        thisElement.getW(), thisElement);
+                        thisElement.getWidth(), thisElement);
             }
 
             if (thisBreak.bpdAdjust != 0
@@ -967,7 +989,7 @@
         int partial = 0;
         while (spaceListIterator.hasNext()) {
             KnuthGlue blockSpace = (KnuthGlue)spaceListIterator.next();
-            partial += (difference > 0 ? blockSpace.getY() : blockSpace.getZ());
+            partial += (difference > 0 ? blockSpace.getStretch() : blockSpace.getShrink());
             if (log.isDebugEnabled()) {
                 log.debug("available = " + partial +  " / " + total);
                 log.debug("competenza  = "
@@ -990,7 +1012,7 @@
         int partial = 0;
         while (lineListIterator.hasNext()) {
             KnuthGlue line = (KnuthGlue)lineListIterator.next();
-            partial += (difference > 0 ? line.getY() : line.getZ());
+            partial += (difference > 0 ? line.getStretch() : line.getShrink());
             int newAdjust = ((BlockLevelLayoutManager) line.getLayoutManager()).negotiateBPDAdjustment(((int) ((float) partial * difference / total)) - adjustedDiff, line);
             adjustedDiff += newAdjust;
         }
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index e86c5fe..3378d86 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -1133,7 +1133,7 @@
                     // by this BlockLM, and must be ignored
                     if (element.getLayoutManager() != this) {
                         splitList.add(element);
-                        splitLength += element.getW();
+                        splitLength += element.getWidth();
                         lastLM = element.getLayoutManager();
                     }
                 }
diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
index 53dc5b3..d7453a3 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
@@ -339,7 +339,7 @@
                 // by this BlockLM, and must be ignored
                 if (element.getLayoutManager() != this) {
                     splitList.add(element);
-                    splitLength += element.getW();
+                    splitLength += element.getWidth();
                     lastLM = element.getLayoutManager();
                 }
             }
diff --git a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
index 9a0dbe2..92a4230 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
@@ -695,11 +695,11 @@
 /*LF*/          //log.debug("  BLM.negotiateBPDAdjustment> bpunit con penalty");
                 KnuthPenalty storedPenalty = (KnuthPenalty)
                                              storedList.get(mappingPos.getLastIndex());
-                if (storedPenalty.getW() > 0) {
+                if (storedPenalty.getWidth() > 0) {
                     // the original penalty has width > 0
 /*LF*/              //log.debug("  BLM.negotiateBPDAdjustment> chiamata passata");
                     return ((BlockLevelLayoutManager)storedPenalty.getLayoutManager())
-                           .negotiateBPDAdjustment(storedPenalty.getW(),
+                           .negotiateBPDAdjustment(storedPenalty.getWidth(),
                                    storedPenalty);
                 } else {
                     // the original penalty has width = 0
@@ -1406,17 +1406,18 @@
         while (oldListIterator.hasNext()) {
             KnuthElement element = (KnuthElement) oldListIterator.next();
             if (element.isBox()) {
-                totalLength.add(new MinOptMax(element.getW()));
-                //log.debug("box " + element.getW());
+                totalLength.add(new MinOptMax(element.getWidth()));
+                //log.debug("box " + element.getWidth());
             } else if (element.isGlue()) {
-                totalLength.min -= element.getZ();
-                totalLength.max += element.getY();
+                totalLength.min -= element.getShrink();
+                totalLength.max += element.getStretch();
                 //leafValue = ((LeafPosition) element.getPosition()).getLeafPos();
-                //log.debug("glue " + element.getW() + " + "
-                //    + ((KnuthGlue) element).getY() + " - " + ((KnuthGlue) element).getZ());
+                //log.debug("glue " + element.getWidth() + " + "
+                //    + ((KnuthGlue) element).getStretch() + " - "
+                //    + ((KnuthGlue) element).getShrink());
             } else {
-                //log.debug((((KnuthPenalty)element).getP() == KnuthElement.INFINITE
-                //    ? "PENALTY " : "penalty ") + element.getW());
+                //log.debug((((KnuthPenalty)element).getPenalty() == KnuthElement.INFINITE
+                //    ? "PENALTY " : "penalty ") + element.getWidth());
             }
         }
         // compute the total amount of "units"
@@ -1443,22 +1444,22 @@
             KnuthElement element = (KnuthElement) oldListIterator.next();
             lastIndex++;
             if (element.isBox()) {
-                lengthBeforeBreak.add(new MinOptMax(element.getW()));
-                lengthAfterBreak.subtract(new MinOptMax(element.getW()));
+                lengthBeforeBreak.add(new MinOptMax(element.getWidth()));
+                lengthAfterBreak.subtract(new MinOptMax(element.getWidth()));
                 bPrevIsBox = true;
             } else if (element.isGlue()) {
-                lengthBeforeBreak.min -= element.getZ();
-                lengthAfterBreak.min += element.getZ();
-                lengthBeforeBreak.max += element.getY();
-                lengthAfterBreak.max -= element.getY();
+                lengthBeforeBreak.min -= element.getShrink();
+                lengthAfterBreak.min += element.getShrink();
+                lengthBeforeBreak.max += element.getStretch();
+                lengthAfterBreak.max -= element.getStretch();
                 bPrevIsBox = false;
             } else {
-                lengthBeforeBreak.add(new MinOptMax(element.getW()));
+                lengthBeforeBreak.add(new MinOptMax(element.getWidth()));
                 bPrevIsBox = false;
             }
 
             // create the new elements
-            if (element.isPenalty() && element.getP() < KnuthElement.INFINITE
+            if (element.isPenalty() && element.getPenalty() < KnuthElement.INFINITE
                     || element.isGlue() && bPrevIsBox
                     || !oldListIterator.hasNext()) {
                 // suppress elements after the breaking point
@@ -1468,8 +1469,8 @@
                     iStepsForward++;
                     if (el.isGlue()) {
                         // suppressed glue
-                        lengthAfterBreak.min += el.getZ();
-                        lengthAfterBreak.max -= el.getY();
+                        lengthAfterBreak.min += el.getShrink();
+                        lengthAfterBreak.max -= el.getStretch();
                     } else if (el.isPenalty()) {
                         // suppressed penalty, do nothing
                     } else {
@@ -1489,8 +1490,8 @@
                 for (int i = 0; i < iStepsForward; i++) {
                     KnuthElement el = (KnuthElement) oldListIterator.previous();
                     if (el.isGlue()) {
-                        lengthAfterBreak.min -= el.getZ();
-                        lengthAfterBreak.max += el.getY();
+                        lengthAfterBreak.min -= el.getShrink();
+                        lengthAfterBreak.max += el.getStretch();
                     }
                 }
 
@@ -1611,7 +1612,7 @@
             }
 
             if (element.isPenalty()) {
-                lengthBeforeBreak.add(new MinOptMax(-element.getW()));
+                lengthBeforeBreak.add(new MinOptMax(-element.getWidth()));
             }
 
         }
@@ -1640,14 +1641,14 @@
                                    - neededUnits(totalLength.opt - adjustedSpaceBefore))
                                   * bpUnit;
             // insert the correct elements
-            newList.addFirst(new KnuthBox(wrongBox.getW() - decreasedLength,
+            newList.addFirst(new KnuthBox(wrongBox.getWidth() - decreasedLength,
                                           wrongBox.getPosition(), false));
             newList.addFirst(new KnuthGlue(decreasedLength, 0, 0, SPACE_BEFORE_ADJUSTMENT,
                                            wrongBox.getPosition(), false));
-            //log.debug("        rimosso box " + neededUnits(wrongBox.getW()));
+            //log.debug("        rimosso box " + neededUnits(wrongBox.getWidth()));
             //log.debug("        aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
             //log.debug("        aggiunto box " + neededUnits(
-            //       wrongBox.getW() - decreasedLength));
+            //       wrongBox.getWidth() - decreasedLength));
         }
 
         // if space-after.conditionality is "discard", correct newList
@@ -1663,7 +1664,7 @@
             // (it cannot be parted and has some stretch or shrink)
             // the wrong box is the first one, not the last one
             LinkedList preserveList = new LinkedList();
-            if (wrongBox.getW() == 0) {
+            if (wrongBox.getWidth() == 0) {
                 preserveList.add(wrongBox);
                 preserveList.addFirst((KnuthGlue) newList.removeLast());
                 preserveList.addFirst((KnuthPenalty) newList.removeLast());
@@ -1676,7 +1677,7 @@
                                    - neededUnits(totalLength.opt - adjustedSpaceAfter))
                                   * bpUnit;
             // insert the correct box
-            newList.addLast(new KnuthBox(wrongBox.getW() - decreasedLength,
+            newList.addLast(new KnuthBox(wrongBox.getWidth() - decreasedLength,
                                          wrongBox.getPosition(), false));
             // add preserved elements
             if (!preserveList.isEmpty()) {
@@ -1685,9 +1686,9 @@
             // insert the correct glue
             newList.addLast(new KnuthGlue(decreasedLength, 0, 0, SPACE_AFTER_ADJUSTMENT,
                                           wrongBox.getPosition(), false));
-            //log.debug("        rimosso box " + neededUnits(wrongBox.getW()));
+            //log.debug("        rimosso box " + neededUnits(wrongBox.getWidth()));
             //log.debug("        aggiunto box " + neededUnits(
-            //      wrongBox.getW() - decreasedLength));
+            //      wrongBox.getWidth() - decreasedLength));
             //log.debug("        aggiunto glue " + neededUnits(decreasedLength) + " 0 0");
         }
 
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index 3a688cc..4516c8d 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
@@ -491,7 +491,7 @@
                     elementIndex, previousIsBox, allowedBreaks).isBox();
 
             if (activeNodeCount == 0) {
-                if (ipdChanged()) {
+                if (getIPDdifference() != 0) {
                     return handleIpdChange();
                 }
                 if (!force) {
@@ -538,8 +538,8 @@
         return line;
     }
 
-    protected boolean ipdChanged() {
-        return false;
+    protected int getIPDdifference() {
+        return 0;
     }
 
     protected int handleIpdChange() {
@@ -676,7 +676,7 @@
     protected void handleBox(KnuthBox box) {
         // a KnuthBox object is not a legal line break,
         // just add the width to the total
-        totalWidth += box.getW();
+        totalWidth += box.getWidth();
     }
 
     /**
@@ -697,9 +697,9 @@
             && !(allowedBreaks == ONLY_FORCED_BREAKS)) {
             considerLegalBreak(glue, position);
         }
-        totalWidth += glue.getW();
-        totalStretch += glue.getY();
-        totalShrink += glue.getZ();
+        totalWidth += glue.getWidth();
+        totalStretch += glue.getStretch();
+        totalShrink += glue.getShrink();
     }
 
     /**
@@ -716,8 +716,8 @@
         // only if its penalty is not infinite;
         // consider all penalties, non-flagged penalties or non-forcing penalties
         // according to the value of allowedBreaks
-        if (((penalty.getP() < KnuthElement.INFINITE)
-                && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isFlagged())
+        if (((penalty.getPenalty() < KnuthElement.INFINITE)
+                && (!(allowedBreaks == NO_FLAGGED_PENALTIES) || !penalty.isPenaltyFlagged())
                 && (!(allowedBreaks == ONLY_FORCED_BREAKS)
                         || penalty.isForcedBreak()))) {
             considerLegalBreak(penalty, position);
@@ -880,7 +880,7 @@
      */
     protected boolean elementCanEndLine(KnuthElement element, int line, int difference) {
         return (!element.isPenalty()
-                || element.getP() < KnuthElement.INFINITE);
+                || element.getPenalty() < KnuthElement.INFINITE);
     }
 
     /**
@@ -921,9 +921,9 @@
             if (tempElement.isBox()) {
                 break;
             } else if (tempElement.isGlue()) {
-                newWidth += tempElement.getW();
-                newStretch += tempElement.getY();
-                newShrink += tempElement.getZ();
+                newWidth += tempElement.getWidth();
+                newStretch += tempElement.getStretch();
+                newShrink += tempElement.getShrink();
             } else if (tempElement.isForcedBreak() && i != elementIdx) {
                 break;
             }
@@ -1034,9 +1034,9 @@
             if (tempElement.isBox()) {
                 break;
             } else if (tempElement.isGlue()) {
-                newWidth += tempElement.getW();
-                newStretch += tempElement.getY();
-                newShrink += tempElement.getZ();
+                newWidth += tempElement.getWidth();
+                newStretch += tempElement.getStretch();
+                newShrink += tempElement.getShrink();
             } else if (tempElement.isForcedBreak() && i != elementIdx) {
                 break;
             }
@@ -1075,7 +1075,7 @@
         // compute the adjustment ratio
         int actualWidth = totalWidth - activeNode.totalWidth;
         if (element.isPenalty()) {
-            actualWidth += element.getW();
+            actualWidth += element.getWidth();
         }
         return getLineWidth() - actualWidth;
     }
@@ -1133,7 +1133,7 @@
         double f = Math.abs(r);
         f = 1 + 100 * f * f * f;
         if (element.isPenalty()) {
-            double penalty = element.getP();
+            double penalty = element.getPenalty();
             if (penalty >= 0) {
                 f += penalty;
                 demerits = f * f;
@@ -1146,9 +1146,9 @@
             demerits = f * f;
         }
 
-        if (element.isPenalty() && ((KnuthPenalty) element).isFlagged()
+        if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged()
             && getElement(activeNode.position).isPenalty()
-            && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) {
+            && ((KnuthPenalty) getElement(activeNode.position)).isPenaltyFlagged()) {
             // add demerit for consecutive breaks at flagged penalties
             demerits += repeatedFlaggedDemerit;
             // there are at least two consecutive lines ending with a flagged penalty;
@@ -1160,7 +1160,7 @@
                  prevNode = prevNode.previous) {
                 KnuthElement prevElement = getElement(prevNode.position);
                 if (prevElement.isPenalty()
-                    && ((KnuthPenalty) prevElement).isFlagged()) {
+                    && ((KnuthPenalty) prevElement).isPenaltyFlagged()) {
                     // the previous line ends with a flagged penalty too
                     flaggedPenaltiesCount++;
                 } else {
diff --git a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
index d3403cd..ca11d27 100644
--- a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
+++ b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
@@ -62,13 +62,14 @@
             if (el.isPenalty()) {
                 KnuthPenalty penalty = (KnuthPenalty)el;
                 //Convert all penalties to break inhibitors
-                if (penalty.getP() < KnuthPenalty.INFINITE) {
-                    iter.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE,
-                            penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
+                if (penalty.getPenalty() < KnuthPenalty.INFINITE) {
+                    iter.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE,
+                            penalty.isPenaltyFlagged(), penalty.getPosition(),
+                            penalty.isAuxiliary()));
                 }
             } else if (el.isGlue()) {
                 KnuthGlue glue = (KnuthGlue)el;
-                len += glue.getW();
+                len += glue.getWidth();
                 iter.previous();
                 el = (ListElement)iter.previous();
                 iter.next();
@@ -84,7 +85,7 @@
                 }
             } else {
                 KnuthElement kel = (KnuthElement)el;
-                len += kel.getW();
+                len += kel.getWidth();
             }
             if (len >= constraint) {
                 return false;
@@ -109,13 +110,14 @@
             if (el.isPenalty()) {
                 KnuthPenalty penalty = (KnuthPenalty)el;
                 //Convert all penalties to break inhibitors
-                if (penalty.getP() < KnuthPenalty.INFINITE) {
-                    i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE,
-                            penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
+                if (penalty.getPenalty() < KnuthPenalty.INFINITE) {
+                    i.set(new KnuthPenalty(penalty.getWidth(), KnuthPenalty.INFINITE,
+                            penalty.isPenaltyFlagged(), penalty.getPosition(),
+                            penalty.isAuxiliary()));
                 }
             } else if (el.isGlue()) {
                 KnuthGlue glue = (KnuthGlue)el;
-                len += glue.getW();
+                len += glue.getWidth();
                 el = (ListElement)i.previous();
                 i.next();
                 if (el.isBox()) {
@@ -134,7 +136,7 @@
                 }
             } else {
                 KnuthElement kel = (KnuthElement)el;
-                len += kel.getW();
+                len += kel.getWidth();
             }
             if (len >= constraint) {
                 return false;
@@ -158,9 +160,9 @@
         while (iter.hasNext()) {
             ListElement el = (ListElement)iter.next();
             if (el.isBox()) {
-                len += ((KnuthElement)el).getW();
+                len += ((KnuthElement)el).getWidth();
             } else if (el.isGlue()) {
-                len += ((KnuthElement)el).getW();
+                len += ((KnuthElement)el).getWidth();
             } else {
                 //log.debug("Ignoring penalty: " + el);
                 //ignore penalties
@@ -210,7 +212,7 @@
      */
     public static boolean endsWithNonInfinitePenalty(List elems) {
         ListElement last = (ListElement) ListUtil.getLast(elems);
-        if (last.isPenalty() && ((KnuthPenalty)last).getP() < KnuthElement.INFINITE) {
+        if (last.isPenalty() && ((KnuthPenalty)last).getPenalty() < KnuthElement.INFINITE) {
             return true;
         } else if (last instanceof BreakElement
                         && ((BreakElement)last).getPenaltyValue() < KnuthElement.INFINITE) {
@@ -230,7 +232,7 @@
         int prevBreak = startIndex - 1;
         while (prevBreak >= 0) {
             KnuthElement el = (KnuthElement)elems.get(prevBreak);
-            if (el.isPenalty() && el.getP() < KnuthElement.INFINITE) {
+            if (el.isPenalty() && el.getPenalty() < KnuthElement.INFINITE) {
                 break;
             }
             prevBreak--;
diff --git a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
index 104c711..0d00b71 100644
--- a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
+++ b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
@@ -72,7 +72,7 @@
         lastOldElement = getLast();
         firstNewElement = sequence.getElement(0);
         if (firstNewElement.isBox() && !((KnuthElement) firstNewElement).isAuxiliary()
-                && lastOldElement.isBox() && ((KnuthElement) lastOldElement).getW() != 0) {
+                && lastOldElement.isBox() && ((KnuthElement) lastOldElement).getWidth() != 0) {
             addALetterSpace();
         }
         addAll(sequence);
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthBox.java b/src/java/org/apache/fop/layoutmgr/KnuthBox.java
index 7c3df61..d7615dd 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthBox.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthBox.java
@@ -37,12 +37,12 @@
     /**
      * Create a new KnuthBox.
      *
-     * @param w    the width of this box
+     * @param width    the width of this box
      * @param pos  the Position stored in this box
-     * @param bAux is this box auxiliary?
+     * @param auxiliary is this box auxiliary?
      */
-    public KnuthBox(int w, Position pos, boolean bAux) {
-        super(w, pos, bAux);
+    public KnuthBox(int width, Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
     }
 
     /** {@inheritDoc} */
@@ -52,14 +52,14 @@
 
     /** {@inheritDoc} */
     public String toString() {
-        StringBuffer sb = new StringBuffer(64);
+        StringBuffer buffer = new StringBuffer(64);
         if (isAuxiliary()) {
-            sb.append("aux. ");
+            buffer.append("aux. ");
         }
-        sb.append("box");
-        sb.append(" w=");
-        sb.append(getW());
-        return sb.toString();
+        buffer.append("box");
+        buffer.append(" w=");
+        buffer.append(getWidth());
+        return buffer.toString();
     }
 
 }
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthElement.java b/src/java/org/apache/fop/layoutmgr/KnuthElement.java
index 41c8130..e8ca6d8 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthElement.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthElement.java
@@ -33,44 +33,44 @@
     public static final int INFINITE = 1000;
 
     private int width;
-    private boolean bIsAuxiliary;
+    private boolean auxiliary;
 
     /**
      * Create a new KnuthElement.
      * This class being abstract, this can be called only by subclasses.
      *
-     * @param w    the width of this element
+     * @param width    the width of this element
      * @param pos  the Position stored in this element
-     * @param bAux is this an auxiliary element?
+     * @param auxiliary is this an auxiliary element?
      */
-    protected KnuthElement(int w, Position pos, boolean bAux) {
+    protected KnuthElement(int width, Position pos, boolean auxiliary) {
         super(pos);
-        width = w;
-        bIsAuxiliary = bAux;
+        this.width = width;
+        this.auxiliary = auxiliary;
     }
 
     /** @return true if this element is an auxiliary one. */
     public boolean isAuxiliary() {
-        return bIsAuxiliary;
+        return auxiliary;
     }
 
     /** @return the width of this element. */
-    public int getW() {
+    public int getWidth() {
         return width;
     }
 
     /** @return the penalty value of this element, if applicable. */
-    public int getP() {
+    public int getPenalty() {
         throw new RuntimeException("Element is not a penalty");
     }
 
     /** @return the stretch value of this element, if applicable. */
-    public int getY() {
+    public int getStretch() {
         throw new RuntimeException("Element is not a glue");
     }
 
     /** @return the shrink value of this element, if applicable. */
-    public int getZ() {
+    public int getShrink() {
         throw new RuntimeException("Element is not a glue");
     }
 
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthGlue.java b/src/java/org/apache/fop/layoutmgr/KnuthGlue.java
index fbb291f..7533a41 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthGlue.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthGlue.java
@@ -54,24 +54,25 @@
     /**
      * Create a new KnuthGlue.
      *
-     * @param w the width of this glue
-     * @param y the stretchability of this glue
-     * @param z the shrinkability of this glue
+     * @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 bAux is this glue auxiliary?
+     * @param auxiliary is this glue auxiliary?
      */
-    public KnuthGlue(int w, int y, int z, Position pos, boolean bAux) {
-        super(w, pos, bAux);
-        stretchability = y;
-        shrinkability = z;
+    public KnuthGlue(int width, int stretchability, int shrinkability, Position pos,
+                     boolean auxiliary) {
+        super(width, pos, auxiliary);
+        this.stretchability = stretchability;
+        this.shrinkability = shrinkability;
     }
 
-    public KnuthGlue(int w, int y, int z,
-            int iAdjClass, Position pos, boolean bAux) {
-        super(w, pos, bAux);
-        stretchability = y;
-        shrinkability = z;
-        adjustmentClass = iAdjClass;
+    public KnuthGlue(int width, int stretchability, int shrinkability, int adjustmentClass,
+                     Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
+        this.stretchability = stretchability;
+        this.shrinkability = shrinkability;
+        this.adjustmentClass = adjustmentClass;
     }
 
     /** {@inheritDoc} */
@@ -80,12 +81,12 @@
     }
 
     /** @return the stretchability of this glue. */
-    public int getY() {
+    public int getStretch() {
         return stretchability;
     }
 
     /** @return the shrinkability of this glue. */
-    public int getZ() {
+    public int getShrink() {
         return shrinkability;
     }
 
@@ -96,18 +97,18 @@
 
     /** {@inheritDoc} */
     public String toString() {
-        StringBuffer sb = new StringBuffer(64);
+        StringBuffer buffer = new StringBuffer(64);
         if (isAuxiliary()) {
-            sb.append("aux. ");
+            buffer.append("aux. ");
         }
-        sb.append("glue");
-        sb.append(" w=").append(getW());
-        sb.append(" stretch=").append(getY());
-        sb.append(" shrink=").append(getZ());
+        buffer.append("glue");
+        buffer.append(" w=").append(getWidth());
+        buffer.append(" stretch=").append(getStretch());
+        buffer.append(" shrink=").append(getShrink());
         if (getAdjustmentClass() >= 0) {
-            sb.append(" adj-class=").append(getAdjustmentClass());
+            buffer.append(" adj-class=").append(getAdjustmentClass());
         }
-        return sb.toString();
+        return buffer.toString();
     }
 
 }
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java b/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
index 9031b6b..c17e9c7 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
@@ -45,39 +45,40 @@
     public static final int FLAGGED_PENALTY = 50;
 
     private int penalty;
-    private boolean isFlagged;
+    private boolean penaltyFlagged;
     private int breakClass = -1;
 
     /**
      * Create a new KnuthPenalty.
      *
-     * @param w the width of this penalty
-     * @param p the penalty value of this penalty
-     * @param f is this penalty flagged?
+     * @param width the width of this penalty
+     * @param penalty the penalty value of this penalty
+     * @param penaltyFlagged is this penalty flagged?
      * @param pos the Position stored in this penalty
-     * @param isAuxiliary is this penalty auxiliary?
+     * @param auxiliary is this penalty auxiliary?
      */
-    public KnuthPenalty(int w, int p, boolean f, Position pos, boolean isAuxiliary) {
-        super(w, pos, isAuxiliary);
-        penalty = p;
-        isFlagged = f;
+    public KnuthPenalty(int width, int penalty, boolean penaltyFlagged, Position pos,
+                        boolean auxiliary) {
+        super(width, pos, auxiliary);
+        this.penalty = penalty;
+        this.penaltyFlagged = penaltyFlagged;
     }
 
     /**
      * Create a new KnuthPenalty.
      *
-     * @param w the width of this penalty
-     * @param p the penalty value of this penalty
-     * @param f is this penalty flagged?
+     * @param width the width of this penalty
+     * @param penalty the penalty value of this penalty
+     * @param penaltyFlagged is this penalty flagged?
      * @param breakClass the break class of this penalty (one of
      * {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
      * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE})
      * @param pos the Position stored in this penalty
      * @param isAuxiliary is this penalty auxiliary?
      */
-    public KnuthPenalty(int w, int p, boolean f,
-            int breakClass, Position pos, boolean isAuxiliary) {
-        this(w, p, f, pos, isAuxiliary);
+    public KnuthPenalty(int width, int penalty, boolean penaltyFlagged, int breakClass,
+                        Position pos, boolean isAuxiliary) {
+        this(width, penalty, penaltyFlagged, pos, isAuxiliary);
         this.breakClass = breakClass;
     }
 
@@ -90,6 +91,8 @@
      * (Mainly used in {@link #toString()} methods, to improve readability
      * of the trace logs.)
      *
+     * TODO: shouldn't be penalty a class of its own?
+     *
      * @param penaltyValue  the penalty value
      * @return  the penalty value as a {@link java.lang.String}
      */
@@ -110,21 +113,21 @@
     /**
      * @return the penalty value of this penalty.
      */
-    public int getP() {
+    public int getPenalty() {
         return penalty;
     }
 
     /**
      * Sets a new penalty value.
-     * @param p the new penalty value
+     * @param penalty the new penalty value
      */
-    public void setP(int p) {
-        this.penalty = p;
+    public void setPenalty(int penalty) {
+        this.penalty = penalty;
     }
 
     /** @return true is this penalty is a flagged one. */
-    public boolean isFlagged() {
-        return isFlagged;
+    public boolean isPenaltyFlagged() {
+        return penaltyFlagged;
     }
 
     /** {@inheritDoc} */
@@ -142,28 +145,28 @@
 
     /** {@inheritDoc} */
     public String toString() {
-        StringBuffer sb = new StringBuffer(64);
+        StringBuffer buffer = new StringBuffer(64);
         if (isAuxiliary()) {
-            sb.append("aux. ");
+            buffer.append("aux. ");
         }
-        sb.append("penalty");
-        sb.append(" p=");
-        sb.append(valueOf(this.penalty));
-        if (this.isFlagged) {
-            sb.append(" [flagged]");
+        buffer.append("penalty");
+        buffer.append(" p=");
+        buffer.append(valueOf(this.penalty));
+        if (this.penaltyFlagged) {
+            buffer.append(" [flagged]");
         }
-        sb.append(" w=");
-        sb.append(getW());
+        buffer.append(" w=");
+        buffer.append(getWidth());
         if (isForcedBreak()) {
-            sb.append(" (forced break, ")
+            buffer.append(" (forced break, ")
                     .append(getBreakClassName(this.breakClass))
                     .append(")");
         } else if (this.penalty >= 0 && this.breakClass != -1) {
             //penalty corresponding to a keep constraint
-            sb.append(" (keep constraint, ")
+            buffer.append(" (keep constraint, ")
                     .append(getBreakClassName(this.breakClass))
                     .append(")");
         }
-        return sb.toString();
+        return buffer.toString();
     }
 }
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
index feb6332..7c71204 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthSequence.java
@@ -26,9 +26,12 @@
 import java.util.ListIterator;
 
 /**
- * Represents a list of Knuth elements.
+ * Represents a list of {@link KnuthElement Knuth elements}.
  */
 public abstract class KnuthSequence extends ArrayList {
+
+    //TODO: do not extend ArrayList
+
     /**
      * Creates a new and empty list.
      */
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index 52238e9..83dea01 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -96,7 +96,7 @@
     //Controls whether a single part should be forced if possible (ex. block-container)
     private boolean favorSinglePart = false;
 
-    private boolean ipdChange;
+    private int ipdDifference;
     private KnuthNode bestNodeForIPDChange;
 
     //Used to keep track of switches in keep-context
@@ -320,7 +320,7 @@
          * will not have considered it a legal break, but it could still
          * be one.
          */
-        if (penalty.getP() == KnuthPenalty.INFINITE) {
+        if (penalty.getPenalty() == KnuthPenalty.INFINITE) {
             int breakClass = penalty.getBreakClass();
             if (breakClass == Constants.EN_PAGE
                     || breakClass == Constants.EN_COLUMN) {
@@ -363,7 +363,7 @@
                     noteListIterator.hasNext();) {
                 final KnuthElement element = (KnuthElement) noteListIterator.next();
                 if (element.isBox() || element.isGlue()) {
-                    noteLength += element.getW();
+                    noteLength += element.getWidth();
                 }
             }
             int prevLength = (lengthList == null || lengthList.isEmpty())
@@ -445,22 +445,22 @@
             return true;
         } else {
             KnuthPenalty p = (KnuthPenalty) element;
-            if (p.getP() <= 0) {
+            if (p.getPenalty() <= 0) {
                 return true;
             } else {
                 int context = p.getBreakClass();
                 switch (context) {
                 case Constants.EN_LINE:
                 case Constants.EN_COLUMN:
-                    return p.getP() < KnuthPenalty.INFINITE;
+                    return p.getPenalty() < KnuthPenalty.INFINITE;
                 case Constants.EN_PAGE:
-                    return p.getP() < KnuthPenalty.INFINITE
+                    return p.getPenalty() < KnuthPenalty.INFINITE
                             || !pageProvider.endPage(line - 1);
                 case Constants.EN_AUTO:
                     log.debug("keep is not auto but context is");
                     return true;
                 default:
-                    if (p.getP() < KnuthPenalty.INFINITE) {
+                    if (p.getPenalty() < KnuthPenalty.INFINITE) {
                         log.debug("Non recognized keep context:" + context);
                         return true;
                     } else {
@@ -479,7 +479,7 @@
         int footnoteSplit = 0;
         boolean canDeferOldFootnotes;
         if (element.isPenalty()) {
-            actualWidth += element.getW();
+            actualWidth += element.getWidth();
         }
         if (footnotesPending) {
             // compute the total length of the footnotes not yet inserted
@@ -588,7 +588,7 @@
                  index++) {
                 if (par.getElement(index).isGlue() && par.getElement(index - 1).isBox()
                     || par.getElement(index).isPenalty()
-                       && ((KnuthElement) par.getElement(index)).getP() < KnuthElement.INFINITE) {
+                       && ((KnuthElement) par.getElement(index)).getPenalty() < KnuthElement.INFINITE) {
                     // break found
                     break;
                 }
@@ -711,7 +711,7 @@
                     element = (KnuthElement) noteListIterator.next();
                     if (element.isBox()) {
                         // element is a box
-                        splitLength += element.getW();
+                        splitLength += element.getWidth();
                         boxPreceding = true;
                     } else if (element.isGlue()) {
                         // element is a glue
@@ -721,10 +721,10 @@
                             break;
                         }
                         boxPreceding = false;
-                        splitLength += element.getW();
+                        splitLength += element.getWidth();
                     } else {
                         // element is a penalty
-                        if (element.getP() < KnuthElement.INFINITE) {
+                        if (element.getPenalty() < KnuthElement.INFINITE) {
                             // end of the sub-sequence
                             index = noteListIterator.previousIndex();
                             break;
@@ -792,7 +792,7 @@
         double f = Math.abs(r);
         f = 1 + 100 * f * f * f;
         if (element.isPenalty()) {
-            double penalty = element.getP();
+            double penalty = element.getPenalty();
             if (penalty >= 0) {
                 f += penalty;
                 demerits = f * f;
@@ -805,9 +805,9 @@
             demerits = f * f;
         }
 
-        if (element.isPenalty() && ((KnuthPenalty) element).isFlagged()
+        if (element.isPenalty() && ((KnuthPenalty) element).isPenaltyFlagged()
             && getElement(activeNode.position).isPenalty()
-            && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) {
+            && ((KnuthPenalty) getElement(activeNode.position)).isPenaltyFlagged()) {
             // add demerit for consecutive breaks at flagged penalties
             demerits += repeatedFlaggedDemerit;
         }
@@ -1077,8 +1077,8 @@
     }
 
     /** {@inheritDoc} */
-    protected boolean ipdChanged() {
-        return ipdChange;
+    protected int getIPDdifference() {
+        return ipdDifference;
     }
 
     /** {@inheritDoc} */
@@ -1104,9 +1104,9 @@
      * @param node the active node to add
      */
     protected void addNode(int line, KnuthNode node) {
-        if (node.position < par.size() - 1 && line > 0 && ipdChange(line - 1)) {
+        if (node.position < par.size() - 1 && line > 0
+                && (ipdDifference = compareIPDs(line - 1)) != 0) {
             log.trace("IPD changes at page " + line);
-            ipdChange = true;
             if (bestNodeForIPDChange == null
                     || node.totalDemerits < bestNodeForIPDChange.totalDemerits) {
                 bestNodeForIPDChange = node;
@@ -1117,7 +1117,7 @@
                  * The whole sequence could actually fit on the last page before
                  * the IPD change. No need to do any special handling.
                  */
-                ipdChange = false;
+                ipdDifference = 0;
             }
             super.addNode(line, node);
         }
@@ -1127,12 +1127,11 @@
         return bestNodeForIPDChange;
     }
 
-    /** {@inheritDoc} */
-    protected boolean ipdChange(int line) {
+    private int compareIPDs(int line) {
         if (pageProvider == null) {
-            return false;
+            return 0;
         }
-        return pageProvider.ipdChange(line);
+        return pageProvider.compareIPDs(line);
     }
 
 }
diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java
index bd55636..2e531a8 100644
--- a/src/java/org/apache/fop/layoutmgr/PageProvider.java
+++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java
@@ -161,12 +161,13 @@
     }
 
     /**
-     * Returns true if the part following the given one has a different IPD.
+     * Compares the IPD of the given part with the following one.
      *
      * @param index index of the current part
-     * @return true if the following part has a different IPD, false otherwise
+     * @return a negative integer, zero or a positive integer as the current IPD is less
+     * than, equal to or greater than the IPD of the following part
      */
-    public boolean ipdChange(int index) {
+    public int compareIPDs(int index) {
         int columnCount = 0;
         int colIndex = startColumnOfCurrentElementList + index;
         int pageIndex = -1;
@@ -179,11 +180,11 @@
         } while (colIndex >= columnCount);
         if (colIndex + 1 < columnCount) {
             // Next part is a column on same page => same IPD
-            return false;
+            return 0;
         } else {
             Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
             return page.getPageViewport().getBodyRegion().getIPD()
-                    != nextPage.getPageViewport().getBodyRegion().getIPD();
+                    - nextPage.getPageViewport().getBodyRegion().getIPD();
         }
     }
 
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
index 95f7981..4680f64 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
@@ -266,12 +266,12 @@
                         KnuthSequence ks = (KnuthSequence)obj;
                         for (Iterator it = ks.iterator(); it.hasNext(); ) {
                             contentElement = (KnuthElement)it.next();
-                            stackSize += contentElement.getW();
+                            stackSize += contentElement.getWidth();
                             contentList.add(contentElement);
                         }
                     } else {
                         contentElement = (KnuthElement)obj;
-                        stackSize += contentElement.getW();
+                        stackSize += contentElement.getWidth();
                         contentList.add(contentElement);
                     }
                 }
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index 7c30ab9..0b95ef8 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
@@ -680,7 +680,7 @@
                     assert lastElement != null;
                     previousIsBox = lastElement.isBox()
                             && !((KnuthElement) lastElement).isAuxiliary()
-                            && ((KnuthElement) lastElement).getW() != 0;
+                            && ((KnuthElement) lastElement).getWidth() != 0;
 
                     // if last paragraph is open, add the new elements to the paragraph
                     // else this is the last paragraph
@@ -705,7 +705,7 @@
 
                     // finish last paragraph if it was closed with a linefeed
                     if (lastElement.isPenalty()
-                            && ((KnuthPenalty) lastElement).getP() == -KnuthPenalty.INFINITE) {
+                            && ((KnuthPenalty) lastElement).getPenalty() == -KnuthPenalty.INFINITE) {
                         // a penalty item whose value is -inf
                         // represents a preserved linefeed,
                         // which forces a line break
@@ -1172,7 +1172,7 @@
         LeafPosition pos = (LeafPosition)lastElement.getPosition();
         int totalAdj = adj;
         //if (lastElement.isPenalty()) {
-        //    totalAdj += lastElement.getW();
+        //    totalAdj += lastElement.getWidth();
         //}
         //int lineNumberDifference = (int)((double) totalAdj / constantLineHeight);
         int lineNumberDifference = (int) Math.round((double) totalAdj / constantLineHeight
diff --git a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
index b8a2b28..f793bb3 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
@@ -57,6 +57,8 @@
  */
 public class TextLayoutManager extends LeafNodeLayoutManager {
 
+    //TODO: remove all final modifiers at local variables
+
     /**
      * Store information about each potential text area.
      * Index of character which ends the area, IPD of area, including
@@ -703,39 +705,39 @@
     }
 
     private AreaInfo processWord(final int alignment, final KnuthSequence sequence,
-            AreaInfo prevAi, final char ch, final boolean breakOpportunity,
+            AreaInfo prevAreaInfo, final char ch, final boolean breakOpportunity,
             final boolean checkEndsWithHyphen) {
-        AreaInfo ai;
+
         //Word boundary found, process widths and kerning
         int lastIndex = this.nextStart;
         while (lastIndex > 0
-                && this.foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
+                && foText.charAt(lastIndex - 1) == CharUtilities.SOFT_HYPHEN) {
             lastIndex--;
         }
         final boolean endsWithHyphen = checkEndsWithHyphen
-                && this.foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
+                && foText.charAt(lastIndex) == CharUtilities.SOFT_HYPHEN;
         final Font font = FontSelector
-                .selectFontForCharactersInText(this.foText,
-                        this.thisStart, lastIndex, this.foText, this);
+                .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 c = this.foText.charAt(i);
+            final char currentChar = foText.charAt(i);
 
             //character width
-            final int charWidth = font.getCharWidth(c);
+            final int charWidth = font.getCharWidth(currentChar);
             wordIPD.add(charWidth);
 
             //kerning
             if (kerning) {
                 int kern = 0;
                 if (i > this.thisStart) {
-                    final char previous = this.foText.charAt(i - 1);
-                    kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
-                } else if (prevAi != null && !prevAi.isSpace && prevAi.breakIndex > 0) {
-                    final char previous = this.foText.charAt(prevAi.breakIndex - 1);
-                    kern = font.getKernValue(previous, c) * font.getFontSize() / 1000;
+                    final 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);
+                    kern = font.getKernValue(previousChar, currentChar);
                 }
                 if (kern != 0) {
                     this.addToLetterAdjust(i, kern);
@@ -748,11 +750,10 @@
                 && !TextLayoutManager.isSpace(ch)
                 && lastIndex > 0
                 && endsWithHyphen) {
-            final int kern = font.getKernValue(
-                    this.foText.charAt(lastIndex - 1), ch)
-                    * font.getFontSize() / 1000;
+            final int kern = font.getKernValue(foText.charAt(lastIndex - 1), ch);
             if (kern != 0) {
                 this.addToLetterAdjust(lastIndex, kern);
+                //TODO: add kern to wordIPD?
             }
         }
         int iLetterSpaces = wordLength - 1;
@@ -765,20 +766,20 @@
         wordIPD.add(MinOptMax.multiply(this.letterSpaceIPD, iLetterSpaces));
 
         // create the AreaInfo object
-        ai = new AreaInfo(this.thisStart, lastIndex, 0,
+        AreaInfo areaInfo = new AreaInfo(this.thisStart, lastIndex, 0,
                 iLetterSpaces, wordIPD,
                 endsWithHyphen,
                 false, breakOpportunity, font);
-        prevAi = ai;
-        this.vecAreaInfo.add(ai);
+        prevAreaInfo = areaInfo;
+        this.vecAreaInfo.add(areaInfo);
         this.tempStart = this.nextStart;
 
         //add the elements
-        this.addElementsForAWordFragment(sequence, alignment, ai,
+        this.addElementsForAWordFragment(sequence, alignment, areaInfo,
                 this.vecAreaInfo.size() - 1, this.letterSpaceIPD);
-        ai = null;
         this.thisStart = this.nextStart;
-        return prevAi;
+
+        return prevAreaInfo;
     }
 
     /** {@inheritDoc} */
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
index fb88bb7..9848584c 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
@@ -298,14 +298,14 @@
             int stepPenalty = 0;
             KnuthElement endEl = (KnuthElement)elementLists[0].get(end[0]);
             if (endEl instanceof KnuthPenalty) {
-                additionalPenaltyHeight = endEl.getW();
-                stepPenalty = Math.max(stepPenalty, endEl.getP());
+                additionalPenaltyHeight = endEl.getWidth();
+                stepPenalty = Math.max(stepPenalty, endEl.getPenalty());
             }
             endEl = (KnuthElement)elementLists[1].get(end[1]);
             if (endEl instanceof KnuthPenalty) {
                 additionalPenaltyHeight = Math.max(
-                        additionalPenaltyHeight, endEl.getW());
-                stepPenalty = Math.max(stepPenalty, endEl.getP());
+                        additionalPenaltyHeight, endEl.getWidth());
+                stepPenalty = Math.max(stepPenalty, endEl.getPenalty());
             }
 
             int boxHeight = step - addedBoxHeight - penaltyHeight;
@@ -367,7 +367,7 @@
                 end[i]++;
                 KnuthElement el = (KnuthElement)elementLists[i].get(end[i]);
                 if (el.isPenalty()) {
-                    if (el.getP() < KnuthElement.INFINITE) {
+                    if (el.getPenalty() < KnuthElement.INFINITE) {
                         //First legal break point
                         break;
                     }
@@ -379,9 +379,9 @@
                             break;
                         }
                     }
-                    partialHeights[i] += el.getW();
+                    partialHeights[i] += el.getWidth();
                 } else {
-                    partialHeights[i] += el.getW();
+                    partialHeights[i] += el.getWidth();
                 }
             }
             if (end[i] < start[i]) {
diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
index 53e798e..f249d76 100644
--- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
+++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
@@ -158,9 +158,9 @@
         private int contentLength;
 
         FillerPenalty(KnuthPenalty p, int length) {
-            super(length, p.getP(), p.isFlagged(), p.getBreakClass(),
+            super(length, p.getPenalty(), p.isPenaltyFlagged(), p.getBreakClass(),
                     p.getPosition(), p.isAuxiliary());
-            contentLength = p.getW();
+            contentLength = p.getWidth();
         }
 
         FillerPenalty(int length) {
@@ -190,7 +190,7 @@
         } else if (el instanceof FillerBox) {
             return 0;
         } else {
-            return el.getW();
+            return el.getWidth();
         }
     }
 
@@ -248,17 +248,17 @@
                 KnuthElement el = (KnuthElement) iter.next();
                 if (el.isBox()) {
                     prevIsBox = true;
-                    cumulateLength += el.getW();
+                    cumulateLength += el.getWidth();
                 } else if (el.isGlue()) {
                     if (prevIsBox) {
                         elementList.add(iter.nextIndex() - 1,
                                 new FillerPenalty(minBPD - cumulateLength));
                     }
                     prevIsBox = false;
-                    cumulateLength += el.getW();
+                    cumulateLength += el.getWidth();
                 } else {
                     prevIsBox = false;
-                    if (cumulateLength + el.getW() < minBPD) {
+                    if (cumulateLength + el.getWidth() < minBPD) {
                         iter.set(new FillerPenalty((KnuthPenalty) el, minBPD - cumulateLength));
                     }
                 }
@@ -314,7 +314,7 @@
             KnuthElement el = (KnuthElement) knuthIter.next();
             if (el.isPenalty()) {
                 prevIsBox = false;
-                if (el.getP() < KnuthElement.INFINITE
+                if (el.getPenalty() < KnuthElement.INFINITE
                         || ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) {
                     // TODO too much is being done in that test, only to handle
                     // keep.within-column properly.
@@ -322,8 +322,8 @@
                     // First legal break point
                     breakFound = true;
                     KnuthPenalty p = (KnuthPenalty) el;
-                    afterNextStep.penaltyLength = p.getW();
-                    afterNextStep.penaltyValue = p.getP();
+                    afterNextStep.penaltyLength = p.getWidth();
+                    afterNextStep.penaltyValue = p.getPenalty();
                     if (p.isForcedBreak()) {
                         afterNextStep.breakClass = p.getBreakClass();
                     }
@@ -333,9 +333,9 @@
                     // Second legal break point
                     breakFound = true;
                 } else {
-                    afterNextStep.contentLength += el.getW();
+                    afterNextStep.contentLength += el.getWidth();
                     if (!boxFound) {
-                        afterNextStep.condBeforeContentLength += el.getW();
+                        afterNextStep.condBeforeContentLength += el.getWidth();
                     }
                 }
                 prevIsBox = false;
@@ -348,7 +348,7 @@
                 }
                 prevIsBox = true;
                 boxFound = true;
-                afterNextStep.contentLength += el.getW();
+                afterNextStep.contentLength += el.getWidth();
             }
         }
         afterNextStep.end = knuthIter.nextIndex() - 1;
diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
index 7e32fdd..b3cb065 100644
--- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
+++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
@@ -361,7 +361,7 @@
                 while (iter.nextIndex() < endIndex) {
                     KnuthElement el = (KnuthElement) iter.next();
                     if (el.isBox() || el.isGlue()) {
-                        len += el.getW();
+                        len += el.getWidth();
                     }
                 }
                 len += ActiveCell.getElementContentLength((KnuthElement) iter.next());
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
index 4e3c0b1..ea2e64a 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
@@ -202,7 +202,7 @@
         if (lastItem.isForcedBreak()) {
             KnuthPenalty p = (KnuthPenalty) lastItem;
             primaryGridUnit.setBreakAfter(p.getBreakClass());
-            p.setP(0);
+            p.setPenalty(0);
         }
 
         setFinished(true);
diff --git a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java
index 79ed10f..faef636 100644
--- a/src/java/org/apache/fop/pdf/PDFFontNonBase14.java
+++ b/src/java/org/apache/fop/pdf/PDFFontNonBase14.java
@@ -76,7 +76,7 @@
         if (getDocumentSafely().getProfile().isFontEmbeddingRequired()) {
             if (this.getDescriptor().getFontFile() == null) {
                 throw new PDFConformanceException("For " + getDocumentSafely().getProfile()
-                    + ", all fonts have to be embedded!");
+                    + ", all fonts have to be embedded! Offending font: " + getBaseFont());
             }
         }
     }
diff --git a/src/java/org/apache/fop/render/afp/AFPCustomizable.java b/src/java/org/apache/fop/render/afp/AFPCustomizable.java
index ed1ea44..5f3fe68 100644
--- a/src/java/org/apache/fop/render/afp/AFPCustomizable.java
+++ b/src/java/org/apache/fop/render/afp/AFPCustomizable.java
@@ -51,6 +51,14 @@
     void setNativeImagesSupported(boolean nativeImages);
 
     /**
+     * Controls whether CMYK images (IOCA FS45) are enabled. By default, support is disabled
+     * for wider compatibility. When disabled, any CMYK image is converted to the selected
+     * color format.
+     * @param value true to enabled CMYK images
+     */
+    void setCMYKImagesSupported(boolean value);
+
+    /**
      * Sets the shading mode for painting filled rectangles.
      * @param shadingMode the shading mode
      */
diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
index 1f7a732..3fec25d 100644
--- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
+++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java
@@ -357,6 +357,11 @@
     }
 
     /** {@inheritDoc} */
+    public void setCMYKImagesSupported(boolean value) {
+        paintingState.setCMYKImagesSupported(value);
+    }
+
+    /** {@inheritDoc} */
     public void setShadingMode(AFPShadingMode shadingMode) {
         this.shadingMode = shadingMode;
     }
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
index 99ede8e..fcfc9c6 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRawStream.java
@@ -24,6 +24,7 @@
 import org.apache.xmlgraphics.image.loader.impl.ImageRawEPS;
 import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
 import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
+import org.apache.xmlgraphics.util.MimeConstants;
 
 import org.apache.fop.afp.AFPDataObjectInfo;
 import org.apache.fop.render.RenderingContext;
@@ -35,6 +36,7 @@
 
     private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
         ImageFlavor.RAW_JPEG,
+        ImageFlavor.RAW_TIFF,
         ImageFlavor.RAW_EPS,
     };
 
@@ -63,7 +65,12 @@
         if (targetContext instanceof AFPRenderingContext) {
             AFPRenderingContext afpContext = (AFPRenderingContext)targetContext;
             return (afpContext.getPaintingState().isNativeImagesSupported())
-                && (image == null || image instanceof ImageRawJPEG || image instanceof ImageRawEPS);
+                && (image == null
+                        || image instanceof ImageRawJPEG
+                        || image instanceof ImageRawEPS
+                        || ((image instanceof ImageRawStream)
+                                && (MimeConstants.MIME_TIFF.equals(
+                                        ((ImageRawStream)image).getMimeType()))));
         }
         return false;
     }
diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
index 8f79185..b0988e7 100644
--- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
+++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java
@@ -89,7 +89,11 @@
         int resolution = paintingState.getResolution();
         int maxPixelSize = paintingState.getBitsPerPixel();
         if (paintingState.isColorImages()) {
-            maxPixelSize *= 3; //RGB only at the moment
+            if (paintingState.isCMYKImagesSupported()) {
+                maxPixelSize *= 4; //CMYK is maximum
+            } else {
+                maxPixelSize *= 3; //RGB is maximum
+            }
         }
         RenderedImage renderedImage = imageRendered.getRenderedImage();
 
@@ -97,6 +101,7 @@
         ImageSize intrinsicSize = imageInfo.getSize();
 
         boolean useFS10 = (maxPixelSize == 1) || BitmapImageUtil.isMonochromeImage(renderedImage);
+        int functionSet = useFS10 ? 10 : 11;
         boolean usePageSegments = useFS10
                     && !imageObjectInfo.getResourceInfo().getLevel().isInline();
 
@@ -124,11 +129,6 @@
                         resampledDim.width, resampledDim.height, resolution);
             }
         }
-        if (useFS10) {
-            imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10);
-        } else {
-            imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
-        }
 
         imageObjectInfo.setDataHeightRes((int)Math.round(
                 effIntrinsicSize.getDpiHorizontal() * 10));
@@ -156,9 +156,9 @@
         byte[] imageData = null;
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         boolean allowDirectEncoding = true;
-        if (allowDirectEncoding && pixelSize <= maxPixelSize) {
+        if (allowDirectEncoding && (pixelSize <= maxPixelSize)) {
             //Attempt to encode without resampling the image
-            ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage);
+            ImageEncodingHelper helper = new ImageEncodingHelper(renderedImage, pixelSize == 32);
             ColorModel encodedColorModel = helper.getEncodedColorModel();
             boolean directEncode = true;
             if (helper.getEncodedColorModel().getPixelSize() > maxPixelSize) {
@@ -180,6 +180,9 @@
                     log.trace("set subtractive mode");
                     imageObjectInfo.setSubtractive(true);
                 }
+                if (pixelSize == 32) {
+                    functionSet = 45; //IOCA FS45 required for CMYK
+                }
 
                 helper.encode(baos);
                 imageData = baos.toByteArray();
@@ -191,6 +194,7 @@
             //Convert image to 24bit RGB
             ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, baos);
             imageData = baos.toByteArray();
+            imageObjectInfo.setBitsPerPixel(24);
 
             boolean colorImages = paintingState.isColorImages();
             imageObjectInfo.setColor(colorImages);
@@ -212,6 +216,20 @@
             }
         }
 
+        switch (functionSet) {
+        case 10:
+            imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS10);
+            break;
+        case 11:
+            imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS11);
+            break;
+        case 45:
+            imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45);
+            break;
+        default:
+            throw new IllegalStateException("Invalid IOCA function set: " + functionSet);
+        }
+
         imageObjectInfo.setData(imageData);
 
         // set object area info
diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java
index f019c6a..250ff96 100644
--- a/src/java/org/apache/fop/render/afp/AFPRenderer.java
+++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java
@@ -90,8 +90,8 @@
 import org.apache.fop.render.afp.extensions.AFPExtensionAttachment;
 import org.apache.fop.render.afp.extensions.AFPIncludeFormMap;
 import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap;
-import org.apache.fop.render.afp.extensions.AFPPageSetup;
 import org.apache.fop.render.afp.extensions.AFPPageOverlay;
+import org.apache.fop.render.afp.extensions.AFPPageSetup;
 
 /**
  * This is an implementation of a FOP Renderer that renders areas to AFP.
@@ -444,6 +444,7 @@
         ImageFlavor.XML_DOM,
         /*ImageFlavor.RAW_PNG, */ // PNG not natively supported in AFP
         ImageFlavor.RAW_JPEG, ImageFlavor.RAW_CCITTFAX, ImageFlavor.RAW_EPS,
+        ImageFlavor.RAW_TIFF,
         ImageFlavor.GRAPHICS2D, ImageFlavor.BUFFERED_IMAGE, ImageFlavor.RENDERED_IMAGE };
 
     private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
@@ -831,6 +832,11 @@
     }
 
     /** {@inheritDoc} */
+    public void setCMYKImagesSupported(boolean value) {
+        paintingState.setCMYKImagesSupported(value);
+    }
+
+    /** {@inheritDoc} */
     public void setShadingMode(AFPShadingMode shadingMode) {
         this.shadingMode = shadingMode;
     }
diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
index 49e51b3..1e15d4c 100644
--- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
+++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java
@@ -318,6 +318,9 @@
         String imagesMode = imagesCfg.getAttribute("mode", IMAGES_MODE_GRAYSCALE);
         if (IMAGES_MODE_COLOR.equals(imagesMode)) {
             customizable.setColorImages(true);
+
+            boolean cmyk = imagesCfg.getAttributeAsBoolean("cmyk", false);
+            customizable.setCMYKImagesSupported(cmyk);
         } else {
             customizable.setColorImages(false);
             // default to 8 bits per pixel
diff --git a/src/java/org/apache/fop/tools/anttasks/Fop.java b/src/java/org/apache/fop/tools/anttasks/Fop.java
index da25478..cfb8c8a 100644
--- a/src/java/org/apache/fop/tools/anttasks/Fop.java
+++ b/src/java/org/apache/fop/tools/anttasks/Fop.java
@@ -34,6 +34,7 @@
 import java.io.OutputStream;
 import java.net.MalformedURLException;
 import java.util.List;
+import java.util.Vector;
 
 // FOP
 import org.apache.fop.apps.FOPException;
@@ -67,7 +68,10 @@
 public class Fop extends Task {
 
     private File foFile;
-    private List filesets = new java.util.ArrayList();
+    private File xmlFile;
+    private File xsltFile;
+    private String xsltParams;
+    private List/*<FileSet>*/ filesets = new java.util.ArrayList/*<FileSet>*/();
     private File outFile;
     private File outDir;
     private String format; //MIME type
@@ -112,6 +116,54 @@
     }
 
     /**
+     * Gets the input XML file.
+     * @return the input XML file.
+     */
+    public File getXmlFile() {
+        return xmlFile;
+    }
+
+    /**
+     * Sets the input XML file.
+     * @param xmlFile the input XML file.
+     */
+    public void setXmlFile(File xmlFile) {
+        this.xmlFile = xmlFile;
+    }
+
+    /**
+     * Gets the input XSLT file.
+     * @return the input XSLT file.
+     */
+    public File getXsltFile() {
+        return xsltFile;
+    }
+
+    /**
+     * Sets the input XSLT file.
+     * @param xsltFile the input XSLT file.
+     */
+    public void setXsltFile(File xsltFile) {
+        this.xsltFile = xsltFile;
+    }
+
+    /**
+     * Gets the XSLT parameters
+     * @return the XSLT parameters
+     */
+    public String getXsltParams() {
+        return xsltParams;
+    }
+
+    /**
+     * Sets the XSLT parameters 
+     * @param xsltParams the XSLT parameters
+     */
+    public void setXsltParams(String xsltParams) {
+        this.xsltParams = xsltParams;
+    }
+
+    /**
      * Adds a set of XSL-FO files (nested fileset attribute).
      * @param set a fileset
      */
@@ -491,10 +543,39 @@
                     skippedcount++;
                 }
             }
+        } else if (task.getXmlFile() != null && task.getXsltFile() != null) {
+            if (task.getXmlFile().exists() && task.getXsltFile().exists()) {
+                File outf = task.getOutfile();
+                if (outf == null) {
+                    throw new BuildException("outfile is required when fofile is used");
+                }
+                if (task.getOutdir() != null) {
+                    outf = new File(task.getOutdir(), outf.getName());
+                }
+                // Render if "force" flag is set OR
+                // OR output file doesn't exist OR
+                // output file is older than input file
+                if (task.getForce() || !outf.exists()
+                    || (task.getXmlFile().lastModified() > outf.lastModified() ||
+                            task.getXsltFile().lastModified() > outf.lastModified())) {
+                    render(task.getXmlFile(), task.getXsltFile(), outf, outputFormat);
+                    actioncount++;
+                } else if (outf.exists()
+                        && (task.getXmlFile().lastModified() <= outf.lastModified() ||
+                                task.getXsltFile().lastModified() <= outf.lastModified())) {
+                    skippedcount++;
+                }
+            }
         }
 
         GlobPatternMapper mapper = new GlobPatternMapper();
-        mapper.setFrom("*.fo");
+
+        String inputExtension = ".fo";
+        File xsltFile = task.getXsltFile();
+        if (xsltFile != null) {
+            inputExtension = ".xml";
+        }
+        mapper.setFrom("*" + inputExtension);
         mapper.setTo("*" + newExtension);
 
         // deal with the filesets
@@ -507,16 +588,19 @@
                 File f = new File(fs.getDir(task.getProject()), files[j]);
 
                 File outf = null;
-                if (task.getOutdir() != null && files[j].endsWith(".fo")) {
+                if (task.getOutdir() != null && files[j].endsWith(inputExtension)) {
                   String[] sa = mapper.mapFileName(files[j]);
                   outf = new File(task.getOutdir(), sa[0]);
                 } else {
-                  outf = replaceExtension(f, ".fo", newExtension);
+                  outf = replaceExtension(f, inputExtension, newExtension);
                   if (task.getOutdir() != null) {
                       outf = new File(task.getOutdir(), outf.getName());
                   }
                 }
-
+                File dir = outf.getParentFile();
+                if (!dir.exists()) {
+                    dir.mkdirs();
+                }
                 try {
                     if (task.getRelativebase()) {
                         this.baseURL = f.getParentFile().toURI().toURL().
@@ -536,7 +620,11 @@
                 // output file is older than input file
                 if (task.getForce() || !outf.exists()
                     || (f.lastModified() > outf.lastModified() )) {
-                    render(f, outf, outputFormat);
+                    if (xsltFile != null) {
+                        render(f, xsltFile, outf, outputFormat);
+                    } else {
+                        render(f, outf, outputFormat);
+                    }
                     actioncount++;
                 } else if (outf.exists() && (f.lastModified() <= outf.lastModified() )) {
                     skippedcount++;
@@ -554,10 +642,7 @@
         }
     }
 
-    private void render(File foFile, File outFile,
-                        String outputFormat) throws FOPException {
-        InputHandler inputHandler = new InputHandler(foFile);
-
+    private void renderInputHandler(InputHandler inputHandler, File outFile, String outputFormat) throws Exception {
         OutputStream out = null;
         try {
             out = new java.io.FileOutputStream(outFile);
@@ -565,11 +650,6 @@
         } catch (Exception ex) {
             throw new BuildException("Failed to open " + outFile, ex);
         }
-
-        if (task.getLogFiles()) {
-            task.log(foFile + " -> " + outFile, Project.MSG_INFO);
-        }
-
         boolean success = false;
         try {
             FOUserAgent userAgent = fopFactory.newFOUserAgent();
@@ -580,7 +660,7 @@
             if (task.getThrowexceptions()) {
                 throw new BuildException(ex);
             }
-            logger.error("Error rendering fo file: " + foFile, ex);
+            throw ex;
         } finally {
             try {
                 out.close();
@@ -593,5 +673,31 @@
         }
     }
 
+    private void render(File foFile, File outFile,
+                        String outputFormat) throws FOPException {
+        InputHandler inputHandler = new InputHandler(foFile);
+        try {
+            renderInputHandler(inputHandler, outFile, outputFormat);
+        } catch (Exception ex) {
+            logger.error("Error rendering fo file: " + foFile, ex);
+        }
+        if (task.getLogFiles()) {
+            task.log(foFile + " -> " + outFile, Project.MSG_INFO);
+        }
+    }
+
+    private void render(File xmlFile, File xsltFile, File outFile, String outputFormat) {
+        //TODO: implement support for XSLT params
+        final Vector xsltParams = null;
+        InputHandler inputHandler = new InputHandler(xmlFile, xsltFile, xsltParams);
+        try {
+            renderInputHandler(inputHandler, outFile, outputFormat);
+        } catch (Exception ex) {
+            logger.error("Error rendering xml/xslt files: " + xmlFile + ", " + xsltFile, ex);
+        }
+        if (task.getLogFiles()) {
+            task.log("xml: " + xmlFile + ", xslt: " + xsltFile + " -> " + outFile, Project.MSG_INFO);
+        }
+    }
 }
 
diff --git a/status.xml b/status.xml
index 326b750..2586753 100644
--- a/status.xml
+++ b/status.xml
@@ -61,6 +61,18 @@
       <action context="Renderers" dev="JM" type="add" fixes-bug="46705" due-to="Jost Klopfstein">
         Added basic accessibility and Tagged PDF support. 
       </action>
+      <action context="Code" dev="JM" type="add">
+        Added support for encoding CMYK bitmap images (IOCA FS45) and TIFF images as embedded objects.
+      </action>
+      <action context="Code" dev="AC" type="add">
+        Added support for xmlfile and xsltfile parameters in FOP's Ant Task.
+      </action>
+      <action context="Renderers" dev="AC" type="fix" fixes-bug="47941">
+        BugFix: Maintain valid AFP by providing TLE truncation on Attribute Value Triplet values that are greater than 250 chars in length.
+      </action>
+      <action context="Fonts" dev="JM" type="fix" fixes-bug="47711" due-to="Nicolas Peninguy">
+        Fixed generation of CIDSet object in PDF output.
+      </action>
       <action context="Layout" dev="VH" type="fix">
         Fixed handling of percentage values for provisional-label-separation.
       </action>
diff --git a/test/java/org/apache/fop/layoutengine/ElementListCheck.java b/test/java/org/apache/fop/layoutengine/ElementListCheck.java
index 1b6077c..e63fc32 100644
--- a/test/java/org/apache/fop/layoutengine/ElementListCheck.java
+++ b/test/java/org/apache/fop/layoutengine/ElementListCheck.java
@@ -83,10 +83,10 @@
                     }
                     if (domEl.getAttribute("w").length() > 0) {
                         int w = Integer.parseInt(domEl.getAttribute("w"));
-                        if (w != knuthEl.getW()) {
+                        if (w != knuthEl.getWidth()) {
                             fail("Expected w=" + w
                                     + " at position " + pos
-                                    + " but got: " + knuthEl.getW());
+                                    + " but got: " + knuthEl.getWidth());
                         }
                     }
                     if ("true".equals(domEl.getAttribute("aux"))) {
@@ -110,24 +110,24 @@
                     KnuthPenalty pen = (KnuthPenalty)knuthEl;
                     if (domEl.getAttribute("w").length() > 0) {
                         int w = Integer.parseInt(domEl.getAttribute("w"));
-                        if (w != knuthEl.getW()) {
+                        if (w != knuthEl.getWidth()) {
                             fail("Expected w=" + w
                                     + " at position " + pos
-                                    + " but got: " + knuthEl.getW());
+                                    + " but got: " + knuthEl.getWidth());
                         }
                     }
                     if (domEl.getAttribute("p").length() > 0) {
                         if ("<0".equals(domEl.getAttribute("p"))) {
-                            if (knuthEl.getP() >= 0) {
+                            if (knuthEl.getPenalty() >= 0) {
                                 fail("Expected p<0"
                                         + " at position " + pos
-                                        + " but got: " + knuthEl.getP());
+                                        + " but got: " + knuthEl.getPenalty());
                             }
                         } else if (">0".equals(domEl.getAttribute("p"))) {
-                            if (knuthEl.getP() <= 0) {
+                            if (knuthEl.getPenalty() <= 0) {
                                 fail("Expected p>0"
                                         + " at position " + pos
-                                        + " but got: " + knuthEl.getP());
+                                        + " but got: " + knuthEl.getPenalty());
                             }
                         } else {
                             int p;
@@ -142,20 +142,20 @@
                             } else {
                                 p = Integer.parseInt(domEl.getAttribute("p"));
                             }
-                            if (p != knuthEl.getP()) {
+                            if (p != knuthEl.getPenalty()) {
                                 fail("Expected p=" + p
                                         + " at position " + pos
-                                        + " but got: " + knuthEl.getP());
+                                        + " but got: " + knuthEl.getPenalty());
                             }
                         }
                     }
                     if ("true".equals(domEl.getAttribute("flagged"))) {
-                        if (!pen.isFlagged()) {
+                        if (!pen.isPenaltyFlagged()) {
                             fail("Expected flagged penalty"
                                     + " at position " + pos);
                         }
                     } else if ("false".equals(domEl.getAttribute("flagged"))) {
-                        if (pen.isFlagged()) {
+                        if (pen.isPenaltyFlagged()) {
                             fail("Expected non-flagged penalty"
                                     + " at position " + pos);
                         }
@@ -180,26 +180,26 @@
                     KnuthGlue glue = (KnuthGlue)knuthEl;
                     if (domEl.getAttribute("w").length() > 0) {
                         int w = Integer.parseInt(domEl.getAttribute("w"));
-                        if (w != knuthEl.getW()) {
+                        if (w != knuthEl.getWidth()) {
                             fail("Expected w=" + w
                                     + " at position " + pos
-                                    + " but got: " + knuthEl.getW());
+                                    + " but got: " + knuthEl.getWidth());
                         }
                     }
                     if (domEl.getAttribute("y").length() > 0) {
                         int stretch = Integer.parseInt(domEl.getAttribute("y"));
-                        if (stretch != knuthEl.getY()) {
+                        if (stretch != knuthEl.getStretch()) {
                             fail("Expected y=" + stretch
                                     + " (stretch) at position " + pos
-                                    + " but got: " + knuthEl.getY());
+                                    + " but got: " + knuthEl.getStretch());
                         }
                     }
                     if (domEl.getAttribute("z").length() > 0) {
                         int shrink = Integer.parseInt(domEl.getAttribute("z"));
-                        if (shrink != knuthEl.getZ()) {
+                        if (shrink != knuthEl.getShrink()) {
                             fail("Expected z=" + shrink
                                     + " (shrink) at position " + pos
-                                    + " but got: " + knuthEl.getZ());
+                                    + " but got: " + knuthEl.getShrink());
                         }
                     }
                 } else {
diff --git a/test/java/org/apache/fop/util/ElementListUtilsTestCase.java b/test/java/org/apache/fop/util/ElementListUtilsTestCase.java
index d41e9f9..bebad44 100644
--- a/test/java/org/apache/fop/util/ElementListUtilsTestCase.java
+++ b/test/java/org/apache/fop/util/ElementListUtilsTestCase.java
@@ -55,9 +55,9 @@
 
         assertFalse(res);
 
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getP());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
-        assertEquals(0, ((KnuthPenalty)lst.get(5)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getPenalty());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getPenalty());
+        assertEquals(0, ((KnuthPenalty)lst.get(5)).getPenalty());
     }
 
     /**
@@ -82,11 +82,11 @@
         assertFalse(res);
 
         //Must insert an INFINITE penalty
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getP());
-        assertEquals(0, ((KnuthGlue)lst.get(2)).getW());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(4)).getP());
-        assertEquals(0, ((KnuthGlue)lst.get(5)).getW());
-        assertEquals(0, ((KnuthGlue)lst.get(7)).getW());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getPenalty());
+        assertEquals(0, ((KnuthGlue)lst.get(2)).getWidth());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(4)).getPenalty());
+        assertEquals(0, ((KnuthGlue)lst.get(5)).getWidth());
+        assertEquals(0, ((KnuthGlue)lst.get(7)).getWidth());
     }
 
     /**
@@ -110,9 +110,9 @@
 
         assertFalse(res);
 
-        assertEquals(0, ((KnuthPenalty)lst.get(1)).getP());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getP());
+        assertEquals(0, ((KnuthPenalty)lst.get(1)).getPenalty());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getPenalty());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getPenalty());
     }
 
     /**
@@ -137,10 +137,10 @@
         assertFalse(res);
 
         //Must insert an INFINITE penalty
-        assertEquals(0, ((KnuthPenalty)lst.get(1)).getP());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
-        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getP());
-        assertEquals(0, ((KnuthGlue)lst.get(6)).getW());
+        assertEquals(0, ((KnuthPenalty)lst.get(1)).getPenalty());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getPenalty());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getPenalty());
+        assertEquals(0, ((KnuthGlue)lst.get(6)).getWidth());
     }
 
 
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_no-restartable.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_no-restartable.xml
new file mode 100644
index 0000000..576a73a
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_no-restartable.xml
@@ -0,0 +1,404 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks that the code behaves properly when no restartable element can be found at 
+      all after a changing IPD break.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-size="8pt" line-height="10pt" 
+      provisional-distance-between-starts="6pt" provisional-label-separation="0">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="narrow"
+          page-height="70pt" page-width="320pt" margin="10pt">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+        <fo:simple-page-master master-name="wide"
+          page-height="70pt" page-width="420pt" margin="10pt">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+        <fo:page-sequence-master master-name="start-narrow-rest-wide">
+          <fo:single-page-master-reference master-reference="narrow"/>
+          <fo:repeatable-page-master-reference master-reference="wide"/>
+        </fo:page-sequence-master>
+        <fo:page-sequence-master master-name="alternate">
+          <fo:repeatable-page-master-alternatives>
+            <fo:conditional-page-master-reference master-reference="narrow" odd-or-even="odd"/>
+            <fo:conditional-page-master-reference master-reference="wide" odd-or-even="even"/>
+          </fo:repeatable-page-master-alternatives>
+        </fo:page-sequence-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="start-narrow-rest-wide">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the table</fo:block>
+          <fo:table table-layout="fixed" width="100%">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>
+                    <fo:block>Before page break</fo:block>
+                    <fo:block>After page break</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+      <fo:page-sequence master-reference="start-narrow-rest-wide">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the table</fo:block>
+          <fo:table table-layout="fixed" width="100%">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>
+                    <fo:block>Before page break</fo:block>
+                    <fo:block>After page break</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 1</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 2</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 3</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 4</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 5</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 6</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 7</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+      <fo:page-sequence master-reference="alternate">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the table</fo:block>
+          <fo:table table-layout="fixed" width="100%">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>
+                    <fo:block>Before page break</fo:block>
+                    <fo:block>After page break</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 1</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 2</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 3</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 4</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 5</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 6</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>Fill 7</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+      <fo:page-sequence master-reference="start-narrow-rest-wide">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the list</fo:block>
+          <fo:list-block>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Before page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>After page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+      <fo:page-sequence master-reference="start-narrow-rest-wide">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the list</fo:block>
+          <fo:list-block>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Before page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>After page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 1</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 2</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 3</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 4</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 5</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 6</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 7</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+      <fo:page-sequence master-reference="alternate">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-after="30pt">Before the list</fo:block>
+          <fo:list-block>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Before page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>After page break</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 1</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 2</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 3</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 4</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 5</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 6</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Fill 7</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+
+    <!-- Tables -->
+    <eval expected="Before page break" xpath="//pageSequence[1]/pageViewport[1]//flow/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//text"/>
+
+    <eval expected="Before page break" xpath="//pageSequence[2]/pageViewport[1]//flow/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[2]/pageViewport[2]//flow/block/block[1]//text"/>
+    <eval expected="Fill 1"            xpath="//pageSequence[2]/pageViewport[2]//flow/block/block[2]//text"/>
+    <eval expected="Fill 2"            xpath="//pageSequence[2]/pageViewport[2]//flow/block/block[3]//text"/>
+    <eval expected="Fill 3"            xpath="//pageSequence[2]/pageViewport[2]//flow/block/block[4]//text"/>
+    <eval expected="Fill 4"            xpath="//pageSequence[2]/pageViewport[2]//flow/block/block[5]//text"/>
+    <eval expected="Fill 5"            xpath="//pageSequence[2]/pageViewport[3]//flow/block/block[1]//text"/>
+    <eval expected="Fill 6"            xpath="//pageSequence[2]/pageViewport[3]//flow/block/block[2]//text"/>
+    <eval expected="Fill 7"            xpath="//pageSequence[2]/pageViewport[3]//flow/block/block[3]//text"/>
+
+    <eval expected="Before page break" xpath="//pageSequence[3]/pageViewport[1]//flow/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[3]/pageViewport[2]//flow/block/block[1]//text"/>
+    <eval expected="Fill 1"            xpath="//pageSequence[3]/pageViewport[2]//flow/block/block[2]//text"/>
+    <eval expected="Fill 2"            xpath="//pageSequence[3]/pageViewport[2]//flow/block/block[3]//text"/>
+    <eval expected="Fill 3"            xpath="//pageSequence[3]/pageViewport[2]//flow/block/block[4]//text"/>
+    <eval expected="Fill 4"            xpath="//pageSequence[3]/pageViewport[2]//flow/block/block[5]//text"/>
+    <eval expected="Fill 5"            xpath="//pageSequence[3]/pageViewport[3]//flow/block/block[1]//text"/>
+    <eval expected="Fill 6"            xpath="//pageSequence[3]/pageViewport[3]//flow/block/block[2]//text"/>
+    <eval expected="Fill 7"            xpath="//pageSequence[3]/pageViewport[3]//flow/block/block[3]//text"/>
+
+    <!-- Lists -->
+    <eval expected="Before page break" xpath="//pageSequence[4]/pageViewport[1]//flow/block[2]/block/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[4]/pageViewport[2]//flow/block[1]/block/block[2]//text"/>
+
+    <eval expected="Before page break" xpath="//pageSequence[5]/pageViewport[1]//flow/block[2]/block/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[5]/pageViewport[2]//flow/block/block[1]/block[2]//text"/>
+    <eval expected="Fill 1"            xpath="//pageSequence[5]/pageViewport[2]//flow/block/block[2]/block[2]//text"/>
+    <eval expected="Fill 2"            xpath="//pageSequence[5]/pageViewport[2]//flow/block/block[3]/block[2]//text"/>
+    <eval expected="Fill 3"            xpath="//pageSequence[5]/pageViewport[2]//flow/block/block[4]/block[2]//text"/>
+    <eval expected="Fill 4"            xpath="//pageSequence[5]/pageViewport[2]//flow/block/block[5]/block[2]//text"/>
+    <eval expected="Fill 5"            xpath="//pageSequence[5]/pageViewport[3]//flow/block/block[1]/block[2]//text"/>
+    <eval expected="Fill 6"            xpath="//pageSequence[5]/pageViewport[3]//flow/block/block[2]/block[2]//text"/>
+    <eval expected="Fill 7"            xpath="//pageSequence[5]/pageViewport[3]//flow/block/block[3]/block[2]//text"/>
+
+    <eval expected="Before page break" xpath="//pageSequence[6]/pageViewport[1]//flow/block[2]/block/block[2]//text"/>
+    <eval expected="After page break"  xpath="//pageSequence[6]/pageViewport[2]//flow/block/block[1]/block[2]//text"/>
+    <eval expected="Fill 1"            xpath="//pageSequence[6]/pageViewport[2]//flow/block/block[2]/block[2]//text"/>
+    <eval expected="Fill 2"            xpath="//pageSequence[6]/pageViewport[2]//flow/block/block[3]/block[2]//text"/>
+    <eval expected="Fill 3"            xpath="//pageSequence[6]/pageViewport[2]//flow/block/block[4]/block[2]//text"/>
+    <eval expected="Fill 4"            xpath="//pageSequence[6]/pageViewport[2]//flow/block/block[5]/block[2]//text"/>
+    <eval expected="Fill 5"            xpath="//pageSequence[6]/pageViewport[3]//flow/block/block[1]/block[2]//text"/>
+    <eval expected="Fill 6"            xpath="//pageSequence[6]/pageViewport[3]//flow/block/block[2]/block[2]//text"/>
+    <eval expected="Fill 7"            xpath="//pageSequence[6]/pageViewport[3]//flow/block/block[3]/block[2]//text"/>
+
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml
new file mode 100644
index 0000000..956563e
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_table-after-break.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks that a table immediately following a changing IPD break is handled properly.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="narrow"
+          page-height="220pt" page-width="320pt" margin="10pt">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+        <fo:simple-page-master master-name="wide"
+          page-height="220pt" page-width="420pt" margin="10pt">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+        <fo:page-sequence-master master-name="pages">
+          <fo:single-page-master-reference master-reference="narrow"/>
+          <fo:repeatable-page-master-reference master-reference="wide"/>
+        </fo:page-sequence-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="pages" font-size="8pt" line-height="10pt">
+        <fo:flow flow-name="xsl-region-body" text-align="justify">
+          <fo:block space-after="180pt">Before the table</fo:block>
+          <fo:table table-layout="fixed" width="100%" id="table">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>
+                    <fo:block id="before_break">Block before the page break.</fo:block>
+                    <fo:block id="after_break">Block after the page break.</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+          <fo:table table-layout="fixed" width="100%">
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>After the table 1</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>After the table 2</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="Block before the page break." xpath="//pageViewport[1]//flow/block[2]//text"/>
+    <eval expected="Block after the page break."  xpath="//pageViewport[2]//flow/block[1]//text"/>
+    <eval expected="After the table 1"            xpath="//pageViewport[2]//flow/block[2]/block[1]//text"/>
+    <eval expected="After the table 2"            xpath="//pageViewport[2]//flow/block[2]/block[2]//text"/>
+  </checks>
+</testcase>