[Mathieu Malaterre]
> It would be nice to start integrating up to date patch from the famous
> issue #2469 in fop so that Debian user get the feeling that auto table
> layout is finally supported in fop:
> 
> https://issues.apache.org/jira/browse/FOP-2469

I had a go at this, using the Debian fop git repository from
<URL: https://salsa.debian.org/java-team/fop.git >.

The patch applied with minimal manual work (two files had changed slightly),
but the code do not build.  This is the build failure:

    [javac] 
/home/pere/src/debian/fop/src/java/org/apache/fop/servlet/FopServlet.java:99: 
error: cannot find symbol
    [javac]         
transFactory.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD, "");
    [javac]                                                         ^
    [javac]   symbol:   variable ACCESS_EXTERNAL_DTD
    [javac]   location: class XMLConstants
    [javac] 
/home/pere/src/debian/fop/src/java/org/apache/fop/servlet/FopServlet.java:100: 
error: cannot find symbol
    [javac]         
transFactory.setAttribute(javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET, 
"");
    [javac]                                                         ^
    [javac]   symbol:   variable ACCESS_EXTERNAL_STYLESHEET
    [javac]   location: class XMLConstants

I see from <URL: 
https://docs.oracle.com/javase/tutorial/jaxp/properties/properties.html >
these were new in JAXP 1.5, but fail to understand why they are not available 
when
building with javac in jdk 10. :(

Any ideas.  My refreshed patch is attached.  Add it to debian/patches/ and list 
it in series
to give it a go yourself.
-- 
Happy hacking
Petter Reinholdtsen
From: https://issues.apache.org/jira/secure/attachment/12738567/2015-06-09-LM-to-LC-refactoring-update.patch

Index: fop/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
===================================================================
--- fop.orig/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java	2018-06-20 04:07:13.807266008 +0000
+++ fop/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java	2018-06-20 04:12:35.027757086 +0000
@@ -19,6 +19,8 @@
 
 package org.apache.fop.fo.flow.table;
 
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.fop.fo.Constants;
@@ -26,7 +28,10 @@
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.Keep;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.table.TableCellLayoutManager;
+import org.apache.fop.layoutmgr.table.TableLayoutManager;
 
 /**
  * This class represents a primary grid unit of a spanned cell. This is the "before-start"
@@ -239,11 +244,9 @@
         return getAfterBorderWidth(getCell().getNumberRowsSpanned() - 1, which);
     }
 
-    /** @return the length of the cell content */
+    /** @return the length of the cell content, auto-layout disallows caching */
     public int getContentLength() {
-        if (contentLength < 0) {
-            contentLength = ElementListUtils.calcContentLength(elements);
-        }
+        contentLength = ElementListUtils.calcContentLength(elements);
         return contentLength;
     }
 
@@ -413,4 +416,43 @@
         this.breakAfter = breakAfter;
     }
 
+	/**
+     * recursively retrieves (and thereby implicitly calculates the dimensions of) all KnuthElements of all
+     * LayoutManagers contained by this {@link PrimaryGridUnit} (i.e. by its 
+     * {@link TableCellLayoutManager}).<br>
+     * Based on {@link #createElementsForRowGroup(LayoutContext, int, int, LinkedList)}.
+     * @param context the layout context to be used to retrieve the {@link KnuthElement}s
+     * @param alignment
+	 * @param tableLM 
+     * @return a list of {@link KnuthElement}s
+     */
+    public List getNextKnuthElementsFromPrimary(LayoutContext context, int alignment, TableLayoutManager tableLM) {
+        this.createCellLM();
+        this.getCellLM().setParent(tableLM);
+        //Calculate width of cell
+        int spanWidth = 0;
+        Iterator colIter = tableLM.getTable().getColumns().listIterator(
+                this.getColIndex());
+        for (int i = 0, c = this.getCell().getNumberColumnsSpanned(); i < c; i++) {
+            spanWidth += ((TableColumn) colIter.next()).getColumnWidth().getValue(
+                    tableLM);
+        }
+        LayoutContext childLC = LayoutContext.newInstance();
+        childLC.setChildOfAutoLayoutElement(context.isChildOfAutoLayoutElement());
+        childLC.setInAutoLayoutDeterminationMode(context.isInAutoLayoutDeterminationMode());
+		
+        childLC.setStackLimitBP(context.getStackLimitBP());
+
+        // TODO: ugly workaround to deal with one-column tables which would be rendered broken otherwise
+        if (tableLM.getTable().getColumns().size() == 1) {
+            childLC.setRefIPD(context.getRefIPD());
+        } else {
+            childLC.setRefIPD(spanWidth);
+        }
+
+        //Get the element list for the cell contents
+        List elems = this.getCellLM().getNextKnuthElements(childLC, alignment);
+        return elems;
+    }
+
 }
Index: fop/src/java/org/apache/fop/fo/flow/table/Table.java
===================================================================
--- fop.orig/src/java/org/apache/fop/fo/flow/table/Table.java	2018-06-20 04:07:13.807266008 +0000
+++ fop/src/java/org/apache/fop/fo/flow/table/Table.java	2018-06-20 04:10:47.518254162 +0000
@@ -152,10 +152,11 @@
             eventProducer.nonAutoBPDOnTable(this, getLocator());
             // Anyway, the bpd of a table is not used by the layout code
         }
-        if (tableLayout == EN_AUTO) {
-            getFOValidationEventProducer().unimplementedFeature(this, getName(),
-                    "table-layout=\"auto\"", getLocator());
-        }
+        // no 'TBD' message required anymore?
+//        if (tableLayout == EN_AUTO) {
+//            getFOValidationEventProducer().unimplementedFeature(this, getName(),
+//                    "table-layout=\"auto\"", getLocator());
+//        }
         if (!isSeparateBorderModel()) {
             if (borderCollapse == EN_COLLAPSE_WITH_PRECEDENCE) {
                 getFOValidationEventProducer().unimplementedFeature(this, getName(),
Index: fop/src/java/org/apache/fop/fo/flow/table/TableColumn.java
===================================================================
--- fop.orig/src/java/org/apache/fop/fo/flow/table/TableColumn.java	2018-06-20 04:07:13.807266008 +0000
+++ fop/src/java/org/apache/fop/fo/flow/table/TableColumn.java	2018-06-20 04:10:47.522254218 +0000
@@ -275,4 +275,7 @@
         return isHeader;
     }
 
+    public final boolean isAutoLayout() {
+        return getColumnWidth() instanceof TableColLength;
+    }
 }
Index: fop/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java	2018-06-20 04:07:13.823266232 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -20,6 +20,7 @@
 package org.apache.fop.layoutmgr;
 
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Stack;
 
 import org.apache.commons.logging.Log;
@@ -280,4 +281,35 @@
     public void recreateChildrenLMs() {
 
     }
+    
+    /** {@inheritDoc} */
+    public boolean isAutoLayout() {
+        final LayoutManager parent = getParent();
+        return parent == null ? false : parent.isAutoLayout();
+    }
+
+//    /** {@inheritDoc} */
+//    public boolean isAutoLayoutDeterminationMode() {
+//        final LayoutManager parent = getParent();
+//        return parent == null ? false : parent.isAutoLayoutDeterminationMode();
+//    }
+
+//    /** {@inheritDoc} */
+//    public boolean hasAutoLayoutParent() {
+//        final LayoutManager parent = getParent();
+//        return parent == null ? false : parent.hasAutoLayoutParent();
+//    }
+
+    /** {@inheritDoc} */
+    public int getMinimumIPD() {
+        int minimumIPD = -1;
+        ListIterator iterLM = getChildLMs().listIterator();
+        while (iterLM.hasNext()) {
+            LayoutManager childLM = (LayoutManager) iterLM.next();
+            int curMinIPD = childLM.getMinimumIPD();
+            minimumIPD = Math.max(minimumIPD, curMinIPD);
+        }
+        return minimumIPD;
+    }
+
 }
Index: fop/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java	2018-06-20 04:07:13.827266288 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.java	2018-06-20 04:10:47.522254218 +0000
@@ -59,6 +59,18 @@
     void rowTooTall(Object source, int row, int effCellBPD, int maxCellBPD, Locator loc);
 
     /**
+     * The minimal width required for the auto-layout of a table's columns is bigger than the available space.
+     * Alternatively: even using the minimal width required for the auto-layout table, its content overflows the
+     * available area by (effIPD - maxIPD) millipoints 
+     * @param source the event source
+     * @param effIPD the effective extent in inline-progression direction of the table contents
+     * @param maxIPD the maximum extent in inline-progression direction available
+     * @param loc the location of the error or null
+     * @event.severity WARN
+     */
+    void columnsInAutoTableTooWide(Object source, int effIPD, int maxIPD, Locator loc);
+    
+    /**
      * Auto-table layout is not supported, yet.
      * @param source the event source
      * @param loc the location of the error or null
Index: fop/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.xml
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.xml	2018-06-20 04:07:13.827266288 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/BlockLevelEventProducer.xml	2018-06-20 04:11:31.658871246 +0000
@@ -33,4 +33,5 @@
   <message key="nonRestartableContentFlowingToNarrowerPage">Content that cannot handle IPD changes is flowing to a narrower page. Part of it may be clipped by the page border.</message>
   <message key="layoutHasReachedParts">A layout has reached {partCount} part(s).</message>
   <message key="lastPageMasterReferenceMissing">page-position="last" master reference missing.{{locator}}</message>
+  <message key="columnsInAutoTableTooWide">The minimal width required for the auto-layout of a table's columns is bigger than the available space ({effIPD}mpt &gt; {maxIPD}mpt). Part of it may overflow the page border. {{locator}}</message>
 </catalogue>
Index: fop/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java	2018-06-20 04:07:13.827266288 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -37,6 +37,7 @@
 import org.apache.fop.fo.properties.KeepProperty;
 import org.apache.fop.fo.properties.SpaceProperty;
 import org.apache.fop.layoutmgr.inline.InlineContainerLayoutManager;
+import org.apache.fop.layoutmgr.inline.LineLayoutManager;
 import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
 import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.util.ListUtil;
@@ -197,7 +198,7 @@
      */
     protected int updateContentAreaIPDwithOverconstrainedAdjust() {
         int ipd = referenceIPD - (startIndent + endIndent);
-        if (ipd < 0) {
+        if (ipd < 0 && !isAutoLayout()) {
             //5.3.4, XSL 1.0, Overconstrained Geometry
             log.debug("Adjusting end-indent based on overconstrained geometry rules for " + fobj);
             BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
@@ -296,6 +297,21 @@
                 emptyStack = true;
             }
 
+            final int ipd = childLC.getRefIPD();
+            if (currentChildLM instanceof LineLayoutManager) {
+//                if (getContentAreaIPD() < ipd && (isAutoLayout() || getParent().hasAutoLayoutParent())) {
+            	if (getContentAreaIPD() < ipd && (isAutoLayout() || context.isChildOfAutoLayoutElement())) {
+                    this.referenceIPD = this.startIndent + ipd + this.endIndent;
+                    updateContentAreaIPDwithOverconstrainedAdjust();
+                    context.setRefIPD(this.referenceIPD);
+                }
+//            } else if (this.referenceIPD < ipd && (isAutoLayout() || getParent().hasAutoLayoutParent())) {
+            } else if (this.referenceIPD < ipd && (isAutoLayout() || context.isChildOfAutoLayoutElement())) {
+                this.referenceIPD = ipd;
+                updateContentAreaIPDwithOverconstrainedAdjust();
+                context.setRefIPD(this.referenceIPD);
+            }
+
             if (contentList.isEmpty()) {
                 // propagate keep-with-previous up from the first child
                 context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
@@ -388,6 +404,8 @@
         childLC.copyPendingMarksFrom(context);
         childLC.setStackLimitBP(context.getStackLimitBP());
         childLC.setRefIPD(referenceIPD);
+        childLC.setChildOfAutoLayoutElement(context.isChildOfAutoLayoutElement());
+        childLC.setInAutoLayoutDeterminationMode(context.isInAutoLayoutDeterminationMode());
         return childLC;
     }
 
Index: fop/src/java/org/apache/fop/layoutmgr/LayoutContext.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/LayoutContext.java	2018-06-20 04:07:13.827266288 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/LayoutContext.java	2018-06-20 04:10:47.522254218 +0000
@@ -125,7 +125,11 @@
 
     private int disableColumnBalancing;
 
-    public static LayoutContext newInstance() {
+	private boolean childOfAutoLayoutElement;
+
+	private boolean inAutoLayoutDeterminationMode;
+
+	public static LayoutContext newInstance() {
         return new LayoutContext(0);
     }
 
@@ -693,5 +697,20 @@
     public void setTreatAsArtifact(boolean treatAsArtifact) {
         setFlags(TREAT_AS_ARTIFACT, treatAsArtifact);
     }
+
+	public void setChildOfAutoLayoutElement(boolean b) {
+		childOfAutoLayoutElement = b;
+	}
+	
+	public boolean isChildOfAutoLayoutElement() {
+		return childOfAutoLayoutElement;
+	}
+	
+	public boolean isInAutoLayoutDeterminationMode() {
+		return inAutoLayoutDeterminationMode;
+	}
+	public void setInAutoLayoutDeterminationMode(boolean b) {
+		inAutoLayoutDeterminationMode = b;
+	}
 }
 
Index: fop/src/java/org/apache/fop/layoutmgr/LayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/LayoutManager.java	2018-06-20 04:07:13.827266288 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/LayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -239,6 +239,11 @@
      * @return the same Position but with a position index
      */
     Position notifyPos(Position pos);
+    
+    /**
+     * @return true if table-layout="auto"
+     */
+    boolean isAutoLayout();
 
     /**
      * Re-initializes this layout manager in order to re-generate its Knuth
@@ -271,4 +276,21 @@
      */
     List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
             Position positionAtIPDChange, LayoutManager restartAtLM);
+
+
+    /**
+     * Iterates over all childLMs to obtain the minimal width required to render all of them (i.e. their content)
+     * without an overflow. 
+     * @return returns the longest required minimal width of all contained layout managers
+     */
+    int getMinimumIPD();
+
+//    /** returns true if any parent of the current {@link LayoutManager} is currently in AutoLayoutDeterminationMode */
+//    boolean isAutoLayoutDeterminationMode();
+
+//    /**
+//     * returns true if any parent of the current {@link LayoutManager} uses automatic layout (which currently only
+//     * applies for tables) and false otherwise.
+//     */
+//    boolean hasAutoLayoutParent();
 }
Index: fop/src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java	2018-06-20 04:07:13.831266343 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/inline/ExternalGraphicLayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -21,6 +21,7 @@
 
 import org.apache.fop.area.Area;
 import org.apache.fop.area.inline.Image;
+import org.apache.fop.area.inline.InlineViewport;
 import org.apache.fop.fo.flow.ExternalGraphic;
 
 
@@ -44,6 +45,17 @@
     protected Area getChildArea() {
         return new Image(((ExternalGraphic) fobj).getSrc());
     }
+    
+    /** {@inheritDoc}<br>TODO: currently only defined for one specific type of image. */
+    public int getMinimumIPD() {
+        if (curArea instanceof InlineViewport) {
+            InlineViewport iVP = (InlineViewport) curArea;
+            return (int) iVP.getContentPosition().getWidth();
+        } else {
+            log.warn("this type does not provide its dimensions, yet.");
+            return 0;
+        }
+    }
 
 }
 
Index: fop/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java	2018-06-20 04:07:13.831266343 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -170,7 +170,7 @@
 
     private LineLayoutPossibilities lineLayouts;
     private LineLayoutPossibilities[] lineLayoutsList;
-    private int ipd;
+    private MinOptMax ipd = null;
     /**
      * When layout must be re-started due to a change of IPD, there is no need
      * to perform hyphenation on the remaining Knuth sequence once again.
@@ -228,8 +228,13 @@
             if (textAlignment == EN_CENTER) {
                 lineFiller = MinOptMax.getInstance(lastLineEndIndent);
             } else {
-                lineFiller = MinOptMax.getInstance(lastLineEndIndent, lastLineEndIndent,
-                        layoutManager.ipd);
+                if (layoutManager.ipd.getOpt() < lastLineEndIndent) {
+                    lineFiller = MinOptMax.getInstance(lastLineEndIndent);
+                } else {
+                    lineFiller = MinOptMax.getInstance(lastLineEndIndent, lastLineEndIndent,
+                        layoutManager.ipd.getOpt());
+                }
+
             }
 
             // add auxiliary elements at the beginning of the paragraph
@@ -443,7 +448,7 @@
             // true if this line contains only zero-height, auxiliary boxes
             // and the actual line width is 0; in this case, the line "collapses"
             // i.e. the line area will have bpd = 0
-            boolean isZeroHeightLine = (difference == ipd);
+            boolean isZeroHeightLine = (difference == ipd.getOpt());
 
             // if line-stacking-strategy is "font-height", the line height
             // is not affected by its content
@@ -499,7 +504,7 @@
                                              firstElementIndex, lastElementIndex,
                                              availableShrink, availableStretch,
                                              difference, ratio, 0, startIndent, endIndent,
-                                             0, ipd, 0, 0, 0);
+                                             0, ipd.getOpt(), 0, 0, 0);
             } else {
                 return new LineBreakPosition(thisLLM,
                                              knuthParagraphs.indexOf(par),
@@ -507,7 +512,7 @@
                                              availableShrink, availableStretch,
                                              difference, ratio, 0, startIndent, endIndent,
                                              lineLead + lineFollow,
-                                             ipd, spaceBefore, spaceAfter,
+                                             ipd.getOpt(), spaceBefore, spaceAfter,
                                              lineLead);
             }
         }
@@ -618,7 +623,7 @@
                     context.getWritingMode());
         }
         context.setAlignmentContext(alignmentContext);
-        ipd = context.getRefIPD();
+        ipd = MinOptMax.getInstance(context.getRefIPD());
 
         //PHASE 1: Create Knuth elements
         if (knuthParagraphs == null) {
@@ -642,6 +647,7 @@
         return createLineBreaks(context.getBPAlignment(), context);
     }
 
+
     /**
      * Get a sequence of KnuthElements representing the content
      * of the node assigned to the LM.
@@ -675,7 +681,7 @@
             return null;
         }
 
-        ipd = context.getRefIPD();
+        ipd = MinOptMax.getInstance(context.getRefIPD());
         //PHASE 2: Create line breaks
         return createLineBreaks(context.getBPAlignment(), context);
     }
@@ -686,6 +692,8 @@
      */
     private void collectInlineKnuthElements(LayoutContext context) {
         LayoutContext inlineLC = LayoutContext.copyOf(context);
+        inlineLC.setChildOfAutoLayoutElement(context.isChildOfAutoLayoutElement());
+        inlineLC.setInAutoLayoutDeterminationMode(context.isInAutoLayoutDeterminationMode());
 
         // convert all the text in a sequence of paragraphs made
         // of KnuthBox, KnuthGlue and KnuthPenalty objects
@@ -695,6 +703,8 @@
 
         Paragraph lastPar = null;
 
+        int minimumIPD = 0;
+        int maxSumIPD = 0;
         InlineLevelLayoutManager curLM;
         while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
             List inlineElements = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
@@ -734,6 +744,22 @@
             ListIterator iter = inlineElements.listIterator();
             while (iter.hasNext()) {
                 KnuthSequence sequence = (KnuthSequence) iter.next();
+
+                // get to know the width of the contained elements
+                if (context.isInAutoLayoutDeterminationMode()) {
+                    final ListIterator i = sequence.listIterator();
+
+                    while (i.hasNext()) {
+                        final KnuthElement element = (KnuthElement) i.next();
+                        // retrieve minimum width for this lineLM along the way
+                        if (element instanceof KnuthBox) {
+                            // TODO: this is already calculated during the collection of the childLM's elements
+                            minimumIPD = Math.max(minimumIPD, element.getWidth());
+                        }
+                        maxSumIPD += element.getWidth();
+                    }
+//                    log.debug("Line with minIPD:=" + minimumIPD);
+                }
                 // the sequence contains inline Knuth elements
                 if (sequence.isInlineSequence()) {
                     // look at the last element
@@ -775,7 +801,7 @@
                         if (!lastPar.containsBox()) {
                             //only a forced linefeed on this line
                             //-> compensate with an auxiliary glue
-                            lastPar.add(new KnuthGlue(ipd, 0, ipd, null, true));
+                            lastPar.add(new KnuthGlue(ipd.getOpt(), 0, ipd.getOpt(), null, true));
                         }
                         lastPar.endParagraph();
                         ElementListObserver.observe(lastPar, "line", null);
@@ -802,6 +828,22 @@
                 trace.append(" ]");
             }
         }
+
+        /**
+         * at this point, localIPD represents the maximum value for how wide the line should be.
+         */
+        if (ipd.getMax() < maxSumIPD && context.isInAutoLayoutDeterminationMode()) {
+            ipd = MinOptMax.getInstance(minimumIPD, maxSumIPD, maxSumIPD);
+
+            final MinOptMax stackLimitBP = context.getStackLimitBP();
+            int max = stackLimitBP.getMax();
+            if (max < maxSumIPD) {
+                max = maxSumIPD;
+            }
+            MinOptMax newStackLimitBP = MinOptMax.getInstance(stackLimitBP.getMin(), maxSumIPD, max);
+            context.setStackLimitBP(newStackLimitBP);
+            context.setRefIPD(ipd.getOpt());
+        }
         log.trace(trace);
     }
 
@@ -835,6 +877,7 @@
         return postProcessLineBreaks(alignment, context);
     }
 
+
     /**
      * Find the optimal linebreaks for a paragraph
      * @param alignment alignment of the paragraph
@@ -855,7 +898,7 @@
                                         hyphenationLadderCount.getEnum() == EN_NO_LIMIT
                                             ? 0 : hyphenationLadderCount.getValue(),
                                         this);
-        alg.setConstantLineWidth(ipd);
+        alg.setConstantLineWidth(ipd.getOpt());
         boolean canWrap = (wrapOption != EN_NO_WRAP);
         boolean canHyphenate = (canWrap && hyphenationProperties.hyphenate.getEnum() == EN_TRUE);
 
@@ -1477,6 +1520,10 @@
             Position pos = parentIter.next();
             boolean isLastPosition = !parentIter.hasNext();
             if (pos instanceof LineBreakPosition) {
+                // propagate the desired space requirements
+                if (isAutoLayout()) {
+                    context.setRefIPD(ipd.getOpt());
+                }
                 addInlineArea(context, (LineBreakPosition) pos, isLastPosition);
             } else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) {
                 addBlockArea(context, pos, isLastPosition);
Index: fop/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java	2018-06-20 04:07:13.831266343 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/inline/TextLayoutManager.java	2018-06-20 04:10:47.522254218 +0000
@@ -131,6 +131,8 @@
 
     private final Position auxiliaryPosition = new LeafPosition(this, -1);
 
+    private int minimumIPD = -1;
+
     /**
      * Create a Text layout manager.
      *
@@ -873,12 +875,42 @@
         if (returnList.isEmpty()) {
             return null;
         } else {
+            determineMinIPD(returnList, context);
             return returnList;
         }
 
 
     }
 
+    /**
+     * Determines the minIPD of the textLM's {@link #foText} by returning the width of its longest string.<br>
+     * TODO: Currently, this dedicated iteration is rather wasteful and should be integrated 
+     * into {@link #getNextKnuthElements(LayoutContext, int)}, if possible. Additionally, the
+     * algorithm is quite trivial and does not take any linebreak possibilities etc. into account.
+     * @param returnList KnuthSequence of KnuthElements representing the object's {@link #foText}
+     * @param context 
+     */
+    private void determineMinIPD(List returnList, LayoutContext context) {
+        minimumIPD = 0;
+        ListIterator iter = returnList.listIterator();
+        while (iter.hasNext()) {
+            KnuthSequence sequence = (KnuthSequence) iter.next();
+
+            if (context.isInAutoLayoutDeterminationMode()) {
+                final ListIterator i = sequence.listIterator();
+
+                while (i.hasNext()) {
+                    final KnuthElement element = (KnuthElement) i.next();
+                    if (element instanceof KnuthBox) {
+                        //TODO: improve algorithm!
+                        minimumIPD = Math.max(minimumIPD, element.getWidth());
+                    }
+                }
+            log.debug("TextLayoutManager with minIPD:=" + minimumIPD);
+            }
+        }
+    }
+
     private KnuthSequence processLinebreak(List returnList, KnuthSequence sequence) {
         if (lineEndBAP != 0) {
             sequence.add(new KnuthGlue(lineEndBAP, 0, 0, auxiliaryPosition, true));
@@ -1465,5 +1497,15 @@
             + ", len = " + foText.length()
             + "}";
     }
+    
+    /**
+     * returns the minimum IPD (aka 'the longest box') required for the line.
+     * Must only be used for table with table-layout="auto".
+     * @return the longest KnuthBox encountered
+     */
+    public int getMinimumIPD() {
+        assert minimumIPD > -1;
+        return minimumIPD;
+    }
 
 }
Index: fop/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java	2018-06-20 04:07:13.835266399 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java	2018-06-20 04:10:47.522254218 +0000
@@ -19,13 +19,13 @@
 
 package org.apache.fop.layoutmgr.table;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.FONode;
@@ -33,7 +33,10 @@
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableColumn;
 import org.apache.fop.fo.properties.TableColLength;
+import org.apache.fop.layoutmgr.BlockLevelEventProducer;
+import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.traits.Direction;
+import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.traits.WritingModeTraits;
 import org.apache.fop.traits.WritingModeTraitsGetter;
 
@@ -47,8 +50,8 @@
 
     private Table table;
     private WritingModeTraitsGetter wmTraits;
-    private List columns = new java.util.ArrayList();
-    private List colWidths = new java.util.ArrayList();
+    private List<TableColumn> columns = new java.util.ArrayList<TableColumn>();
+    private List<Length> colWidths = new java.util.ArrayList<Length>();
 
     private int maxColIndexReferenced;
 
@@ -86,9 +89,9 @@
             //Post-processing the list (looking for gaps)
             //TODO The following block could possibly be removed
             int pos = 1;
-            ListIterator ppIter = columns.listIterator();
+            ListIterator<TableColumn> ppIter = columns.listIterator();
             while (ppIter.hasNext()) {
-                TableColumn col = (TableColumn)ppIter.next();
+                TableColumn col = ppIter.next();
                 if (col == null) {
                     assert false; //Gaps are filled earlier by fo.flow.table.Table.finalizeColumns()
                     //log.error("Found a gap in the table-columns at position " + pos);
@@ -125,9 +128,9 @@
                     }
                 }
             }
-            return (TableColumn) columns.get(size - 1);
+            return columns.get(size - 1);
         } else {
-            return (TableColumn) columns.get(index - 1);
+            return columns.get(index - 1);
         }
     }
 
@@ -146,7 +149,7 @@
    }
 
     /** @return an Iterator over all columns */
-    public Iterator iterator() {
+    public Iterator<TableColumn> iterator() {
         return this.columns.iterator();
     }
 
@@ -174,7 +177,7 @@
 
         for (int i = columns.size(); --i >= 0;) {
             if (columns.get(i) != null) {
-                col = (TableColumn) columns.get(i);
+                col = columns.get(i);
                 colWidth = col.getColumnWidth();
                 colWidths.add(0, colWidth);
             }
@@ -187,10 +190,11 @@
      * [p-c-w(x) = x * base_unit_ipd]
      *
      * @param tlm   the TableLayoutManager
+     * @param context 
      * @return the computed base unit (in millipoint)
      */
-    protected double computeTableUnit(TableLayoutManager tlm) {
-        return computeTableUnit(tlm, tlm.getContentAreaIPD());
+    protected double computeTableUnit(TableLayoutManager tlm, LayoutContext context) {
+        return computeTableUnit(tlm, tlm.getContentAreaIPD(), context);
     }
 
     /**
@@ -199,9 +203,10 @@
      *
      * @param percentBaseContext the percent base context for relative values
      * @param contentAreaIPD the IPD of the available content area
+     * @param context 
      * @return the computed base unit (in millipoints)
      */
-    public float computeTableUnit(PercentBaseContext percentBaseContext, int contentAreaIPD) {
+    public float computeTableUnit(PercentBaseContext percentBaseContext, int contentAreaIPD, LayoutContext context) {
 
         int sumCols = 0;
         float factors = 0;
@@ -211,8 +216,8 @@
          * and work out the total number of factors to use to distribute
          * the remaining space (if any)
          */
-        for (Iterator i = colWidths.iterator(); i.hasNext();) {
-            Length colWidth = (Length) i.next();
+        for (Iterator<Length> i = colWidths.iterator(); i.hasNext();) {
+            Length colWidth = i.next();
             if (colWidth != null) {
                 sumCols += colWidth.getValue(percentBaseContext);
                 if (colWidth instanceof RelativeNumericProperty) {
@@ -230,6 +235,14 @@
             if (sumCols < contentAreaIPD) {
                 unit = (contentAreaIPD - sumCols) / factors;
             } else {
+                // this warning occurs during the preprocessing (AutoLayoutDeterminationMode)
+                // and can be ignored in these cases.
+                if (percentBaseContext instanceof TableLayoutManager) {
+                    TableLayoutManager tlm = (TableLayoutManager) percentBaseContext;
+                    if (context.isInAutoLayoutDeterminationMode()) {
+                        return unit;
+                    }
+                }
                 log.warn("No space remaining to distribute over columns.");
             }
         }
@@ -268,7 +281,7 @@
         for (int i = (col + nrColSpan - 1), nc = colWidths.size(); ++i < nc;) {
             int effCol = i;
             if (colWidths.get(effCol) != null) {
-                xoffset += ((Length) colWidths.get(effCol)).getValue(context);
+                xoffset += colWidths.get(effCol).getValue(context);
             }
         }
         return xoffset;
@@ -289,7 +302,7 @@
                 effCol = colWidths.size() - 1;
             }
             if (colWidths.get(effCol) != null) {
-                xoffset += ((Length) colWidths.get(effCol)).getValue(context);
+                xoffset += colWidths.get(effCol).getValue(context);
             }
         }
         return xoffset;
@@ -308,10 +321,185 @@
                 effIndex = colWidths.size() - 1;
             }
             if (colWidths.get(effIndex) != null) {
-                sum += ((Length) colWidths.get(effIndex)).getValue(context);
+                sum += colWidths.get(effIndex).getValue(context);
             }
         }
         return sum;
     }
 
+    /**
+     * Computes for each of the table's columns the optimal width and adjusts each column if necessary.
+     * This method relies on the fact, that a column's OPT value is initialized equal to its MAX value.
+     * @param tLM
+     * @return int maximum width to be propagated to containing layout manager or -1
+     */
+    public int computeOptimalColumnWidthsForAutoLayout(TableLayoutManager tLM, LayoutContext context) {
+        int maxSumCols = 0; // collects OPT values of the individual columns
+        int minSumCols = 0;
+        int contentAreaIPD = tLM.getContentAreaIPD();
+
+        ListIterator<TableColumn> colIter = columns.listIterator();
+        while (colIter.hasNext()) {
+            TableColumn tcol = colIter.next();
+            if (tcol != null) {
+                if (tcol.isAutoLayout()) {
+                    MinOptMax possibleWidth = tLM.getPossibleWidths(tcol, context);
+                    if (possibleWidth == null) {
+                        // this column does not have a PrimaryGridUnit by itself
+                        // Just assume that no space is required for such an 'empty' column
+                        // TODO: validate this assumption (looks good after rendering it!)
+                    } else {
+                        maxSumCols += possibleWidth.getOpt();
+                        minSumCols += possibleWidth.getMin();
+                    }
+                } else {
+                    int staticWidth = tcol.getColumnWidth().getValue(tLM);
+                    maxSumCols += staticWidth;
+                    minSumCols += staticWidth;
+                }
+            }
+        }
+
+        /*
+         * distribute the remaining space over the accumulated factors (if any)
+         */
+        // TODO: DO NOT DO THIS IN CASE WE ARE IN AN AUTOMATIC LAYOUT PARENT WHICH NEEDS
+        // AUTHENTIC MIN/MAX VALUES TO DETERMINE ITS OWN WIDTH REQUIREMENTS
+//        if (tLM.getParent().hasAutoLayoutParent() && tLM.getParent().isAutoLayoutDeterminationMode()) {
+        if (context.isChildOfAutoLayoutElement() && context.isInAutoLayoutDeterminationMode()) {
+            return maxSumCols;
+        } else {
+            if (maxSumCols >  contentAreaIPD) {
+                if (minSumCols < contentAreaIPD) {
+                    // redistribute by setting OPT values
+                    if (log.isDebugEnabled()) {
+                        log.debug("Sum (" + maxSumCols + ") > Available Area (" + contentAreaIPD + "): Redistributing");
+                    }
+
+                    // create a second list from which we can remove individual items after we are done with them
+                    List<TableColumn> columnsToProcess = new ArrayList<TableColumn>();
+                    columnsToProcess.addAll(columns);
+                    redistribute(tLM, contentAreaIPD, maxSumCols, columnsToProcess, context);
+                } else {
+                    // set all OPTs to the respective MINIMUM of each column
+                    if (minSumCols != contentAreaIPD) {
+                        // communicate this case as a warning to the user 
+                        Table table = tLM.getTable();
+                        BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
+                                table.getUserAgent().getEventBroadcaster());
+                        eventProducer.columnsInAutoTableTooWide(this, minSumCols,
+                                contentAreaIPD, table.getLocator());
+                    }
+                    for (TableColumn tcol : columns) {
+                        if (tcol.isAutoLayout()) {
+                            MinOptMax possibleWidth = tLM.getPossibleWidths(tcol, context);
+                            if (possibleWidth == null) {
+                                // ignore columns which do not contain PGUs -> their width is zero
+                            } else {
+                                int min = possibleWidth.getMin();
+                                int max = possibleWidth.getMax();
+                                MinOptMax minWidth = MinOptMax.getInstance(min, min, max);
+                                tLM.setPossibleWidths(tcol, minWidth);
+                            }
+                        } else {
+                            // DO NOT CHANGE THE OPT-VALUE OF A COLUMN WITH STATIC WIDTH - IT IS
+                            // ALREADY THE STATIC VALUE WE MUST USE (AS DEFINED IN THE FO-FILE)
+                        }
+                    }
+//                    return true;
+                }
+            }
+        }
+//        return false;
+        return -1;
+    }
+
+    /**
+     * This method redistributes the remaining width of the table recursively.
+     * At first, all static columns are excluded (i.e., the redistribution is invoked
+     * for all but these columns), since we cannot shrink them.
+     * Afterwards, we try to proportionally shrink each remaining column by a factor of
+     *     factor = remainingArea / sum of max width of remaining columns
+     * After applying this factor to a column's MAX width, we check if the result is less
+     * than the column's minimal width - if so, this minimal width is used instead and we
+     * invoke the method again with
+     * <ul>
+     *  <li> the remaining columns without the column we just changed</li>
+     *  <li> the remaining area - the minimal width of the column we just changed</li>
+     *  <li> an updated factor (based on the remaining area and the remaining columns)</li>
+     * </ul>
+     * @param tLM the TableLayoutManager which is used to store the dimensions of all columns
+     * @param remainingArea the remaining width which we may still distribute among the columnsToProcess
+     * @param columnsToProcess
+     * @param context 
+     * @return boolean The return value indicates whether the layout changed due to the redistribution.
+     */
+    private boolean redistribute(TableLayoutManager tLM, int remainingArea, int maxSumCols, List<TableColumn> columnsToProcess, LayoutContext context) {
+        double factor = (double) remainingArea / maxSumCols;
+
+        // step 1: check if applying the current factor leads to a value below the minimum of a column
+        for (TableColumn tcol :  columnsToProcess) {
+            // ignore columns which have a static width since we must use their assigned value
+            // ignoring them = excluding them from the columns we want to shrink
+            if (!tcol.isAutoLayout()) {
+                int staticWidth = tcol.getColumnWidth().getValue(tLM);
+                remainingArea -= staticWidth;
+                maxSumCols -= staticWidth;
+                columnsToProcess.remove(tcol);
+                if (log.isDebugEnabled()) {
+                    log.debug("| Col " + tcol.getColumnNumber() + " -> STATIC(" + staticWidth + ") |");
+                }
+                return redistribute(tLM, remainingArea, maxSumCols, columnsToProcess, context);
+            } else {
+                MinOptMax possibleWidth = tLM.getPossibleWidths(tcol, context);
+                if (possibleWidth == null) {
+                    // no PrimaryGridUnits in this column
+                    columnsToProcess.remove(tcol);
+                    if (log.isDebugEnabled()) {
+                        log.debug("| Col " + tcol.getColumnNumber() + " -> EMPTY (0) |");
+                    }
+                    return redistribute(tLM, remainingArea, maxSumCols, columnsToProcess, context);
+                }
+                int max = possibleWidth.getMax();
+                int min = possibleWidth.getMin();
+
+                if ((max * factor) < min) {
+                    // for this column: opt = min
+                    MinOptMax newWidths = MinOptMax.getInstance(min, min, max);
+                    tLM.setPossibleWidths(tcol, newWidths);
+                    // remove this column from the list, decrease the remaining area (-min), and recalculate the factor
+                    remainingArea -= min;
+                    maxSumCols -= max;
+                    // continue with all other columns which may still be shrinked
+                    columnsToProcess.remove(tcol);
+                    if (log.isDebugEnabled()) {
+                        log.debug("| Col " + tcol.getColumnNumber() + " -> MIN(" + min + ") |");
+                    }
+                    return redistribute(tLM, remainingArea, maxSumCols, columnsToProcess, context);
+                } else {
+                    // current column could be shrinked down using the current factor
+                    // however, subsequent columns might not be -> wait until such columns are sorted out
+                }
+            }
+        }
+
+        // step 2: now we know that all remaining columns can be shrinked by the factor
+        for (TableColumn tcol :  columnsToProcess) {
+            MinOptMax possibleWidth = tLM.getPossibleWidths(tcol, context);
+            int max = possibleWidth.getMax();
+            int min = possibleWidth.getMin();
+            int newOpt = (int) (max * factor);
+            if (log.isDebugEnabled()) {
+                log.debug("| Col " + tcol.getColumnNumber() + " -> OPT(" + newOpt + ") |");
+            }
+            MinOptMax newWidths = MinOptMax.getInstance(min, newOpt, max);
+            // ASSIGN to column
+            tLM.setPossibleWidths(tcol, newWidths);
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("Redistribution finished");
+        }
+        return true;
+    }
+
 }
Index: fop/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java	2018-06-20 04:07:13.835266399 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java	2018-06-20 04:10:47.526254273 +0000
@@ -35,6 +35,7 @@
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.ElementListObserver;
+import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.util.BreakUtil;
@@ -115,6 +116,8 @@
                     LayoutContext childLC = LayoutContext.newInstance();
                     childLC.setStackLimitBP(context.getStackLimitBP()); //necessary?
                     childLC.setRefIPD(spanWidth);
+                    childLC.setChildOfAutoLayoutElement(context.isChildOfAutoLayoutElement());
+                    childLC.setInAutoLayoutDeterminationMode(context.isInAutoLayoutDeterminationMode());
 
                     //Get the element list for the cell contents
                     List elems = primary.getCellLM().getNextKnuthElements(
@@ -130,6 +133,7 @@
         returnList.addAll(elements);
     }
 
+
     /**
      * Calculate the heights of the rows in the row group, see CSS21, 17.5.3 Table height
      * algorithms.
Index: fop/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java	2018-06-20 04:07:13.835266399 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java	2018-06-20 04:10:47.526254273 +0000
@@ -22,6 +22,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.ListIterator;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -165,6 +166,36 @@
         return startIndent + endIndent;
     }
 
+    /** {@inheritDoc}<br>Also adds any indents required by the tablecell */
+    public int getMinimumIPD() {
+        int minimumIPD = -1;
+        ListIterator iterLM = getChildLMs().listIterator();
+        while (iterLM.hasNext()) {
+            LayoutManager childLM = (LayoutManager)iterLM.next();
+            int curMinIPD = childLM.getMinimumIPD();
+            minimumIPD = Math.max(minimumIPD, curMinIPD);
+        }
+        minimumIPD += getIPIndents();
+        return minimumIPD;
+    }
+
+    final int getRefIPD() {
+        return this.referenceIPD;
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isAutoLayout() {
+        final Table table = getTable();
+
+        if (table.isAutoLayout()) {
+            final int index = this.primaryGridUnit.getColIndex();
+            final TableColumn column = table.getColumn(index);
+            return column.isAutoLayout();
+        }
+
+        return false;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -186,9 +217,21 @@
             // curLM is a ?
             childLC.setStackLimitBP(context.getStackLimitBP().minus(stackLimit));
             childLC.setRefIPD(cellIPD);
+            childLC.setChildOfAutoLayoutElement(context.isChildOfAutoLayoutElement());
+            childLC.setInAutoLayoutDeterminationMode(context.isInAutoLayoutDeterminationMode());
 
             // get elements from curLM
             returnedList = curLM.getNextKnuthElements(childLC, alignment);
+
+            final int ipd = childLC.getRefIPD() + getIPIndents();
+
+//            if (this.referenceIPD < ipd && (isAutoLayout() || getParent().hasAutoLayoutParent())) {
+            if (this.referenceIPD < ipd && (isAutoLayout() || context.isChildOfAutoLayoutElement())) {
+                this.referenceIPD = ipd;
+                this.cellIPD = getRefIPD() - getIPIndents();
+                context.setRefIPD(ipd);
+            }
+
             if (childLC.isKeepWithNextPending()) {
                 log.debug("child LM signals pending keep with next");
             }
Index: fop/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java	2018-06-20 04:07:13.835266399 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java	2018-06-20 04:10:47.526254273 +0000
@@ -19,6 +19,8 @@
 
 package org.apache.fop.layoutmgr.table;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -27,15 +29,16 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.flow.Marker;
 import org.apache.fop.fo.flow.table.EffRow;
+import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableBody;
+import org.apache.fop.fo.flow.table.TableColumn;
 import org.apache.fop.fo.flow.table.TablePart;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.ElementListUtils;
@@ -53,6 +56,7 @@
 import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition;
+import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.util.BreakUtil;
 
 /**
@@ -77,6 +81,8 @@
 
     private TableStepper stepper;
 
+    private final Map<TableColumn, MinOptMax> baseLength = new HashMap<TableColumn, MinOptMax>();
+
     private boolean headerIsBeingRepeated;
     private boolean  atLeastOnce;
 
@@ -137,6 +143,267 @@
     }
 
     /**
+     * assigns a {@link MinOptMax} object to a specific {@link TableColumn}
+     * @param key a {@link TableColumn}
+     * @param mom a {@link MinOptMax} representing the width requirements of the <code>key</code>
+     */
+    public void setBaseLength(TableColumn key, MinOptMax mom) {
+        this.baseLength.put(key, mom);
+    }
+
+    /**
+     * returns the {@link MinOptMax} assigned to a table's {@link TableColumn}.
+     * @param key a {@link TableColumn}
+     * @return {@link MinOptMax} object representing the minimal, optimal and maximum width required for the
+     * <code>key</code>
+     */
+    public final MinOptMax getBaseLength(final FObj key) {
+        return (MinOptMax) this.baseLength.get(key);
+    }
+
+    /**
+     * Compute and set a set of {@link MinOptMax} widths for a {@link PrimaryGridUnit} (PGU).
+     * Now also covers PGUs spanning multiple columns. However, if such a PGU is encountered
+     * in the first row already, the table requires a second determination run.
+     * @param primary
+     * @return
+     */
+    private boolean setBaseLength(final PrimaryGridUnit primary, LayoutContext context) {
+        final Table table = this.tableLM.getTable();
+        final int index = primary.getColIndex();
+        final int n = index + primary.getCell().getNumberColumnsSpanned();
+        final TableColumn key = table.getColumn(index);
+        
+        int availableSpanWidth = 0;
+        int minSpanWidth = 0;
+
+        int min;
+        int span;
+
+        // calculate width (min and opt) of all columns spanned by primary
+        for (int i = index; i < n; i++) {
+            final TableColumn column = table.getColumn(i);
+            span = column.getColumnWidth().getValue(this.tableLM);
+            availableSpanWidth += span;
+
+            min = span;
+            if (column.isAutoLayout()) {
+                final MinOptMax length = getBaseLength(column);
+                if (length != null) {
+                    min = length.getMin();
+                }
+            }
+            minSpanWidth += min;
+        }
+
+        // retrieve the maximum width of the cell's content - problematic if col-span >1 for a static first column?
+        int ipd = primary.getCellLM().getRefIPD();
+
+        // retrieve the minimum width of the cell's content - also works for cells spanning columns
+        int minIPD = primary.getCellLM().getMinimumIPD();
+
+        final MinOptMax length = getBaseLength(key);
+        if ((availableSpanWidth == 0) || (length == null)) {
+            // TODO: remove the following IF as soon as the computation of minIPD is corrected
+            if (minIPD > ipd) {    // happens e.g. for cells containing a space: ipd=0, minIPD=len(" ")
+                ipd = minIPD;
+            }
+            // |_____c1_____|   <- width for both:    minSpanWidth <= optimal <= availableSpanWidth
+            // |__c2__||___c3___| <- width for spanning cell: minIPD <= optimal <= ipd
+            MinOptMax initialMinOptMax = MinOptMax.getInstance(minIPD, ipd, ipd);
+            this.baseLength.put(key, initialMinOptMax);
+        } else {
+            if (index == n - 1) {    // a primary without col-span > 1
+                if ((availableSpanWidth < ipd) || (length.getMin() < minIPD)) { // cell needs more space
+                    MinOptMax possibleWidths =
+                        MinOptMax.getInstance(
+                                Math.max(length.getMin(), minIPD),
+                                Math.max(length.getOpt(), ipd),
+                                Math.max(length.getMax(), ipd)
+                        );
+                    return length == this.baseLength.put(key, possibleWidths);
+                }
+            } else {
+                // this primary spans multiple columns which may have to be resized!
+                // |__c1__||__c2__|   <- width for both:    minSpanWidth <= optimal <= availableSpanWidth
+                // |__c3 (span=2)___| <- width for spanning cell: minIPD <= optimal <= ipd
+                // thus, if any of the following booleans are true, the spanned columns need to be widened!
+                boolean isNotSufficientForMinIPD = minSpanWidth < minIPD;    // overflow even after linebreaks
+                boolean isNotSufficientForIPD = availableSpanWidth < ipd;    // overflow because of more content
+
+                if (isNotSufficientForMinIPD || isNotSufficientForIPD) {
+                    // columns spanned by the primary do not offer enough width and, thus, need to
+                    // be widened.
+
+                    // first step: ignore static columns which cannot be resized
+                    // this includes removing their width from the widths to process
+                    List<TableColumn> columnsToWiden = new ArrayList<TableColumn>();
+                    for (Iterator iter = table.getColumns().subList(index, n).iterator(); iter.hasNext();) {
+                        TableColumn column = (TableColumn)iter.next();
+                        if (column.isAutoLayout()) {    // column can be resized
+                            int width = column.getColumnWidth().getValue(this.tableLM);
+
+                            if (tableLM.getPossibleWidths(column, context) == null) {
+                                // ignore columns without PrimaryGridUnits
+                            } else {
+                                columnsToWiden.add(column);
+                            }
+                        } else {    // column is static and cannot be resized
+                            int width = column.getColumnWidth().getValue(this.tableLM);
+                            availableSpanWidth -= width;
+                            minSpanWidth -= width;
+                            ipd -= width;
+                            minIPD -= width;
+                        }
+                    }
+
+                    // true if only static columns are spanned -> no columns left to resize!
+                    if (columnsToWiden.isEmpty()) {
+                        LOG.warn("No columns to resize to fit a table-cell spanning these columns, expect overflows");
+                        return false;
+                    }
+
+                    // minimal width reserved by the spanned columns insufficient -> resize
+                    if (minSpanWidth < minIPD) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.warn("Cell (" + primary.getColIndex() + "," + primary.getRowIndex() + ") spanning "
+                                    + primary.getCell().getNumberColumnsSpanned() + " columns requires at least "
+                                    + minIPD + " -> widening MIN/OPT/MAX its spanned columns: " + columnsToWiden);
+                        }
+
+                        int totalIncrease = increaseMinimumWidthOfSpannedColumns(columnsToWiden, minSpanWidth, minIPD, context);
+                        // resizing the columns led to additional space being reserved by these columns!
+                        availableSpanWidth += totalIncrease;
+                    }
+
+                    // maximum width reserved by the spanned columns insufficient -> resize
+                    if (availableSpanWidth < ipd) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.warn("Cell (" + primary.getColIndex() + "," + primary.getRowIndex() + ") spanning "
+                                    + primary.getCell().getNumberColumnsSpanned() + " columns requires up to "
+                                    + ipd + " -> widening OPT/MAX of its spanned columns: " + columnsToWiden);
+                        }
+                        increaseOptimalWidthOfSpannedColumns(columnsToWiden, availableSpanWidth, ipd);
+                    }
+                }
+
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Takes a set of columns (minSpanWidthOfSpannedCells = sum of their minIPDs) which are spanned
+     * by the cell we are currently processing. Since this current cell requires a wider minIPD than
+     * all spanned columns combined, this method increases the min. width of these columns proportionally
+     * in such a way that the sum of their min. widths is >= the minIPD of the current cell.<br>
+     * Please note that for each column, all three values of its {@link MinOptMax} are increased accordingly.
+     * After all columns were processed and widened, the sum of additional space reserved by these columns
+     * is returned.
+     * @param columnsToWiden set of non-static columns which can be resized
+     * @param minSpanWidthOfSpannedCells sum of the minIPDs of the columns in columnsToWiden
+     * @param minIPD minimal width required by the current cell
+     * @param context 
+     * @return the total amount of width which was added to the columns in columnsToWiden
+     */
+    private int increaseMinimumWidthOfSpannedColumns(List columnsToWiden, int minSpanWidthOfSpannedCells, int minIPD, LayoutContext context) {
+        int totalIncrease = 0;
+
+        for (Iterator iter = columnsToWiden.iterator(); iter.hasNext();) {
+            final TableColumn column = (TableColumn) iter.next();
+            MinOptMax length = tableLM.getPossibleWidths(column, context);
+
+            // calculate factor for increase of width
+            double factor = (double)length.getMin() / minSpanWidthOfSpannedCells;
+
+            // how much more space is required to display the spanning cell
+            int totalMissingMinSpace = minIPD - minSpanWidthOfSpannedCells;
+
+            int increaseForMinimum = (int) Math.ceil(factor * totalMissingMinSpace);
+
+            MinOptMax newMom =
+                    MinOptMax.getInstance(
+                            length.getMin() + increaseForMinimum,
+                            length.getOpt() + increaseForMinimum,
+                            length.getMax() + increaseForMinimum
+                    );
+            setBaseLength(column, newMom);
+            totalIncrease += increaseForMinimum;
+        }
+        return totalIncrease;
+    }
+
+    /**
+     * takes a set of columns (<b>columnsToWiden</b>) spanned by one cell (represented via a
+     * {@link PrimaryGridUnit}) and increases their minimum width value (in case the spanning cell's
+     * minIPD is bigger than the sum of
+     * goes through a subset of the columns
+     * @param columnsToWiden
+     * @param availableWidth
+     * @param requiredWidth
+     * @return
+     */
+    private boolean increaseOptimalWidthOfSpannedColumns(List columnsToWiden, int availableWidth, int requiredWidth) {
+        for (Iterator iter = columnsToWiden.iterator(); iter.hasNext();) {
+                final TableColumn column = (TableColumn) iter.next();
+                MinOptMax length = getBaseLength(column);
+
+                // calculate factor for increase of width
+                double factor = (double) length.getOpt() / availableWidth;
+
+                // how much more space is required to display the spanning cell
+                int totalMissingMaxSpace = requiredWidth - availableWidth;
+
+                // ensure the content will fit by getting the ceiling of the product
+                int increase = (int) Math.ceil(factor * totalMissingMaxSpace);
+                MinOptMax newMom =
+                    MinOptMax.getInstance(
+                            length.getMin(),
+                            length.getOpt() + increase,
+                            length.getMax() + increase
+                    );
+                setBaseLength(column, newMom);
+            }
+        return false;
+    }
+
+    private boolean setBaseLength(final TableContentPosition position, LayoutContext context) {
+        boolean done = false;
+        final EffRow row = position.getRow();
+        final Iterator grid = row.getGridUnits().iterator();
+
+        while (grid.hasNext()) {
+            final GridUnit unit = (GridUnit) grid.next();
+
+            if (unit instanceof PrimaryGridUnit) {
+                done = setBaseLength((PrimaryGridUnit) unit, context) || done;
+            }
+        }
+
+        return done;
+    }
+
+    private boolean setBaseLength(final Iterator content,LayoutContext context) {
+        boolean done = false;
+
+        while (content.hasNext()) {
+            final ListElement element = (ListElement) content.next();
+            final Position position = element.getPosition();
+
+            if (position instanceof TableContentPosition) {
+                done = setBaseLength((TableContentPosition) position, context) || done;
+            }
+        }
+
+        return done;
+    }
+
+    public boolean setBaseLength(final List content, LayoutContext context) {
+        final Table table = this.tableLM.getTable();
+        return table.isAutoLayout() && setBaseLength(content.iterator(), context);
+    }
+
+    /**
      * Get a sequence of KnuthElements representing the content
      * of the node assigned to the LM.
      *
@@ -157,6 +424,14 @@
         if (headerIter != null && headerList == null) {
             this.headerList = getKnuthElementsForRowIterator(
                     headerIter, context, alignment, TableRowIterator.HEADER);
+
+            if (setBaseLength(this.headerList, context)) {
+                final Table table = this.tableLM.getTable();
+                this.headerIter = new TableRowIterator(table, TableRowIterator.HEADER);
+                this.headerList = null;
+                return getNextKnuthElements(context, alignment);
+            }
+
             this.headerNetHeight
                     = ElementListUtils.calcContentLength(this.headerList);
             if (LOG.isDebugEnabled()) {
@@ -189,6 +464,20 @@
         if (footerIter != null && footerList == null) {
             this.footerList = getKnuthElementsForRowIterator(
                     footerIter, context, alignment, TableRowIterator.FOOTER);
+
+            if (setBaseLength(this.footerList, context)) {
+                final Table table = this.tableLM.getTable();
+
+                if (this.headerIter != null) {
+                    this.headerIter = new TableRowIterator(table, TableRowIterator.HEADER);
+                    this.headerList = null;
+                }
+
+                this.footerIter = new TableRowIterator(table, TableRowIterator.FOOTER);
+                this.footerList = null;
+                return getNextKnuthElements(context, alignment);
+            }
+            
             this.footerNetHeight
                     = ElementListUtils.calcContentLength(this.footerList);
             if (LOG.isDebugEnabled()) {
@@ -211,6 +500,24 @@
         }
         returnList.addAll(getKnuthElementsForRowIterator(
                 bodyIter, context, alignment, TableRowIterator.BODY));
+
+        if (setBaseLength(returnList, context)) {
+            final Table table = this.tableLM.getTable();
+
+            if (this.headerIter != null) {
+                this.headerIter = new TableRowIterator(table, TableRowIterator.HEADER);
+                this.headerList = null;
+            }
+
+            if (this.footerIter != null) {
+                this.footerIter = new TableRowIterator(table, TableRowIterator.FOOTER);
+                this.footerList = null;
+            }
+
+            this.bodyIter = new TableRowIterator(table, TableRowIterator.BODY);
+            return getNextKnuthElements(context, alignment);
+        }
+
         if (headerAsFirst != null) {
             int insertionPoint = 0;
             if (returnList.size() > 0 && ((ListElement)returnList.getFirst()).isForcedBreak()) {
@@ -599,4 +906,100 @@
         return tableLM.getBaseLength(lengthBase, fobj);
     }
 
+    /**
+     * essentially, do the same things as {@link TableContentLayoutManager#getNextKnuthElements(LayoutContext, int)},
+     * but only do the bare minimum required to get the {@link MinOptMax} values for each column of the
+     * table with automatic layout. Thus, this computation must not have any side effects on the/any
+     * subsequent call to {@link TableContentLayoutManager#getNextKnuthElements(LayoutContext, int)}.
+     * @param childLC
+     * @param alignment
+     */
+    public void determineAutoLayoutWidths(LayoutContext context, int alignment) {
+        Table table = getTableLM().getTable();
+
+        TableRowIterator tempbodyIter = new TableRowIterator(table, TableRowIterator.BODY);
+        TableRowIterator tempheaderIter = null;
+        TableRowIterator tempfooterIter = null;
+
+        if (table.getTableHeader() != null) {
+            tempheaderIter = new TableRowIterator(table, TableRowIterator.HEADER);
+            iterateOverTableRows(tempheaderIter, context, alignment, TableRowIterator.HEADER);
+        }
+
+        iterateOverTableRows(tempbodyIter, context, alignment, TableRowIterator.BODY);
+
+        if (table.getTableFooter() != null) {
+            tempfooterIter = new TableRowIterator(table, TableRowIterator.FOOTER);
+            iterateOverTableRows(tempfooterIter, context, alignment, TableRowIterator.FOOTER);
+        }
+    }
+
+    /**
+     * To be used only during the preprocessing run which determines the dimensions of Tables with table-layout="auto".
+     * Iterates over all rows of the provided iterator (either for the header, footer or body of a table depending
+     * on the parameter <code>bodyType</code>). For each row, the contained {@link PrimaryGridUnit}s are taken to
+     * determine their widths based on their content. These widths are then propagated to the individual 
+     * {@link TableColumn}s via {@link #setBaseLength(PrimaryGridUnit)}. Afterwards, the {@link PrimaryGridUnit}'s 
+     * elements reset so that they are properly processed during the rendering run (this is necessary since the
+     * dimensions obtained for a column are still subject to changes). <br>
+     * Based on
+     * {@link TableContentLayoutManager#getKnuthElementsForRowIterator(TableRowIterator, LayoutContext, int, int)}
+     * However, since we are only interested in the widths of the contained PGUs, most of the original method was
+     * removed.
+     * @param iter Iterator providing access to rows which belong either to the table's body, header or footer
+     * @param context layout context
+     * @param alignment
+     * @param bodyType indicates which part of a table is processed (actually not required)
+     */
+    private void iterateOverTableRows(TableRowIterator iter,    // returns indiv. rows
+            LayoutContext context, int alignment, int bodyType) {
+        EffRow[] rowGroup;
+        List colspanningPGUs = new LinkedList();
+        while ((rowGroup = iter.getNextRowGroup()) != null) {
+            RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
+                    null);    // the actual tablestepper might lead to undesired side effects!
+            /**
+             * based on RowGroupLayoutManager#createElementsForRowGroup
+             * initializes the PGUs of one row at a time
+             */
+            EffRow row;
+            for (int rgi = 0; rgi < rowGroup.length; rgi++) {
+                row = rowGroup[rgi];
+                for (Iterator iterGU = row.getGridUnits().iterator(); iterGU.hasNext();) {
+                    GridUnit gu = (GridUnit) iterGU.next();
+                    if (gu.isPrimary()) {
+                        PrimaryGridUnit primary = gu.getPrimary();
+
+                        // during this iteration, the width of PGUs in the first row which span multiple columns
+                        // cannot be determined and, thus, have to be finished after all other rows are done.
+                        if ((primary.getRowIndex() == 0) && (primary.getCell().getNumberColumnsSpanned() > 1)) {
+                            LOG.debug("Will revisit first row");
+                            colspanningPGUs.add(primary);
+                        }
+                        determineWidthOfPrimary(primary, context, alignment);
+                    }
+                }
+            }
+        }
+        for (Iterator iterPGUs = colspanningPGUs.iterator(); iterPGUs.hasNext();) {
+        	PrimaryGridUnit primary = (PrimaryGridUnit) iterPGUs.next();
+        	determineWidthOfPrimary(primary, context, alignment);
+        }
+        
+    }
+
+	private void determineWidthOfPrimary(PrimaryGridUnit primary, LayoutContext context, int alignment) {
+        // recursively retrieve (and thereby calculate the dimensions of)
+        // all KnuthElements of all contained LayoutManagers for this cell
+    	List elems = primary.getNextKnuthElementsFromPrimary(context, alignment, tableLM);
+
+        // temporarily assign these KnuthElements to the PGU to calculate its dimensions
+        primary.setElements(elems);
+        setBaseLength(primary, context);
+
+        // reset the PGU (and thereby reset (even destroy?) all contained LayoutManagers)
+        // the dimensions, however, are still present in form of a MinOptMax!
+        primary.setElements(null);
+	}
+
 }
Index: fop/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
===================================================================
--- fop.orig/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java	2018-06-20 04:07:13.835266399 +0000
+++ fop/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java	2018-06-20 04:10:47.526254273 +0000
@@ -89,6 +89,8 @@
     private List columnBackgroundAreas;
 
     private Position auxiliaryPosition;
+    
+//    private boolean isAutoLayoutDeterminationMode;
 
     // this holds a possible list of TCLMs that needed to have their addAreas() repeated
     private List<TableCellLayoutManager> savedTCLMs;
@@ -242,7 +244,7 @@
          * for proportional-column-width()
          */
         if (tableUnit == 0.0) {
-            this.tableUnit = columns.computeTableUnit(this);
+            this.tableUnit = columns.computeTableUnit(this, context);
         }
 
         if (!firstVisibleMarkServed) {
@@ -269,7 +271,25 @@
                                  stackSize));*/
         childLC.setRefIPD(context.getRefIPD());
         childLC.copyPendingMarksFrom(context);
+        
+        // width determination is required for any elements in auto-layout containers
+        if (isAutoLayout() || context.isChildOfAutoLayoutElement()) {
+        	childLC.setChildOfAutoLayoutElement(true);
+        	childLC.setInAutoLayoutDeterminationMode(true);
+            contentLM.determineAutoLayoutWidths(childLC, alignment);
+
+            // determination mode ends only if the parent is not still in this mode
+            if (!context.isInAutoLayoutDeterminationMode()) {
+            	childLC.setInAutoLayoutDeterminationMode(false);
+            }
 
+            int maxCol = columns.computeOptimalColumnWidthsForAutoLayout(this, context);
+            // report the determined maximum width to the enquiring parent 
+            if (context.isChildOfAutoLayoutElement() && context.isInAutoLayoutDeterminationMode()) {
+                context.setRefIPD(maxCol);
+            }
+        }
+        
         contentKnuthElements = contentLM.getNextKnuthElements(childLC, alignment);
         //Set index values on elements coming from the content LM
         Iterator iter = contentKnuthElements.iterator();
@@ -500,6 +520,137 @@
         return getTable().getKeepWithNext();
     }
 
+
+    /**
+     * Takes a {@link TableColumn} and looks up its {@link MinOptMax} width values.
+     * However, returns <code>null</code> for {@link TableColumn}s which have a static
+     * width value or any columns which do not have a {@link MinOptMax} object associated
+     * with them (i.e. columns which do not contain a {@link PrimaryGridUnit} but only
+     * {@link GridUnit}s which do not define a width themselves).
+     * @param tcol
+     * @param context 
+     * @return {@link MinOptMax} or <code>null</code>
+     */
+    public MinOptMax getPossibleWidths(TableColumn tcol, LayoutContext context) {
+//        if (this.contentLM != null && (isAutoLayout() || getParent().hasAutoLayoutParent())) {
+    	if (this.contentLM != null && (isAutoLayout() || context.isChildOfAutoLayoutElement())) {
+            if (tcol.isAutoLayout()) {
+                final MinOptMax length = this.contentLM.getBaseLength(tcol);
+                if (length != null) {
+                    return length;
+                }
+            } else {
+                // column uses a static value instead
+                return null;
+            }
+        }
+      /** we may end up here if the table contains cells with invalid columns-spanned attribute
+       * UPDATE: since there is no such thing as an invalid columns-spanned attribute (columns
+       * are simply dynamically added as required) this case cannot be considered to be an error
+       * anymore - simply return null and let the caller take care of this case. */
+//        log.error("Unknown base type for LengthBase. "
+//                + "In your .fo file, please validate the table starting in line " + getTable().getLocator().getLineNumber());
+        return null;
+    }
+    
+    /** {@inheritDoc} */
+    public final boolean isAutoLayout() {
+        return getTable().isAutoLayout();
+    }
+
+//    /**
+//     * indicates whether the current retrieval of KnuthElements is only used to
+//     * determine the dimensions of tables using an automatic layout.
+//     * Became recursive to deal with auto-layout tables in fixed-layout tables
+//     * in auto-layout tables.
+//     * @return true if the rendering process is still in the preprocessing mode
+//     */
+//    public boolean isAutoLayoutDeterminationMode() {
+//        return isAutoLayoutDeterminationMode || getParent().isAutoLayoutDeterminationMode();
+//    }
+
+//    /**
+//     * returns true if the table represented by the {@link TableLayoutManager} uses table-layout="auto" or
+//     * if any parent of this tableLM uses automatic layout 
+//     */
+//    public final boolean hasAutoLayoutParent() {
+//        return getTable().isAutoLayout() || getParent().hasAutoLayoutParent();
+//    }
+    
+    /** {@inheritDoc}<br>Determination is based on the type of layout used for the table. */
+    public int getMinimumIPD() {
+        int minimumIPD = -1;
+        int curMinIPD = 0;
+        if (contentLM != null) {
+            if (this.isAutoLayout()) {
+                curMinIPD = getMinimumIPDforAutoLayout();
+            } else {
+                curMinIPD = getMinimumIPDforFixedLayout();
+            }
+            // TODO: add Indents/Paddings/...
+            minimumIPD = Math.max(minimumIPD, curMinIPD);
+        }
+        return minimumIPD;
+    }
+
+    /**
+     * obtains the width of the widest column and returns this width times the number of columns  
+     * @return width of widest columns times number of columns
+     */
+    private int getMinimumIPDforFixedLayout() {
+        int staticWidth = 0;
+        int widestMinWidthForAutoColumns = 0;
+        int curMinIPD = 0;
+        int autoColumns = 0;
+        for (Iterator<TableColumn> iter = columns.iterator(); iter.hasNext(); ) {
+            TableColumn tcol = iter.next();
+
+            if (!tcol.isAutoLayout()) {
+                // a static column should always requires the same amount of space
+                staticWidth += tcol.getColumnWidth().getValue(this);
+            } else {
+                MinOptMax width = contentLM.getBaseLength(tcol);
+                if (width != null) {
+                    widestMinWidthForAutoColumns = Math.max(widestMinWidthForAutoColumns, width.getMin());
+                }
+                autoColumns++;
+            }
+        }
+        return widestMinWidthForAutoColumns * autoColumns + staticWidth; 
+    }
+
+    /**
+     * obtains the width of each individual column and returns the sum of these widths
+     * @return sum of the width of all columns
+     */
+    private int getMinimumIPDforAutoLayout() {
+        int curMinIPD = 0;
+        for (Iterator<TableColumn> iter = columns.iterator(); iter.hasNext(); ) {
+            TableColumn tcol = iter.next();
+            MinOptMax width = contentLM.getBaseLength(tcol);
+            if (width != null) {
+                curMinIPD += width.getMin();
+            }                
+        }
+        return curMinIPD;
+    }
+    
+    /**
+     * Used only for auto layout tables.
+     * Forwards the new width values ({@link MinOptMax} widths)
+     * of a column to the appropriate {@link TableContentLayoutManager}.
+     * @param tcol {@link TableColumn} which acts as key to get/set the width
+     * @param mom {@link MinOptMax} containing the appropriate values for the column
+     */
+    public void setPossibleWidths(TableColumn tcol, MinOptMax mom) {
+        assert this.contentLM != null;
+        assert isAutoLayout();
+        if (((TableColumn) tcol).isAutoLayout()) {
+            this.contentLM.setBaseLength(tcol, mom);
+        }
+    }
+
+
     // --------- Property Resolution related functions --------- //
 
     /**
@@ -512,6 +663,12 @@
             case LengthBase.CONTAINING_BLOCK_WIDTH:
                 return getContentAreaIPD();
             case LengthBase.TABLE_UNITS:
+                if (this.contentLM != null && isAutoLayout()) {
+                    if (((TableColumn) fobj).isAutoLayout()) {
+                        final MinOptMax length = this.contentLM.getBaseLength(fobj);
+                        return length == null ? 0 : length.getOpt();
+                    }
+                }
                 return (int) this.tableUnit;
             default:
                 log.error("Unknown base type for LengthBase.");
Index: fop/src/java/org/apache/fop/render/rtf/RTFHandler.java
===================================================================
--- fop.orig/src/java/org/apache/fop/render/rtf/RTFHandler.java	2018-06-20 04:07:13.863266791 +0000
+++ fop/src/java/org/apache/fop/render/rtf/RTFHandler.java	2018-06-20 04:10:47.526254273 +0000
@@ -1526,7 +1526,7 @@
         ColumnSetup columnSetup = new ColumnSetup(tab);
         //int sumOfColumns = columnSetup.getSumOfColumnWidths(percentManager);
         float tableWidth = percentManager.getBaseLength(LengthBase.CONTAINING_BLOCK_WIDTH, tab);
-        float tableUnit = columnSetup.computeTableUnit(percentManager, Math.round(tableWidth));
+        float tableUnit = columnSetup.computeTableUnit(percentManager, Math.round(tableWidth), null);
         percentManager.setTableUnit(tab, Math.round(tableUnit));
 
     }
__
This is the maintainer address of Debian's Java team
<https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/pkg-java-maintainers>.
 Please use
debian-j...@lists.debian.org for discussions and questions.

Reply via email to