You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2008/03/06 14:34:59 UTC

svn commit: r634267 [10/39] - in /xmlgraphics/fop/branches/Temp_ProcessingFeedback: ./ examples/embedding/ examples/embedding/java/embedding/ examples/embedding/java/embedding/intermediate/ examples/embedding/xml/xml/ examples/fo/ examples/fo/advanced/...

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java Thu Mar  6 05:33:44 2008
@@ -27,8 +27,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.Trait;
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FObj;
@@ -36,18 +34,17 @@
 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.TableRow;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthBox;
-import org.apache.fop.layoutmgr.KnuthPenalty;
+import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthPossPosIter;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.ListElement;
 import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.PositionIterator;
-import org.apache.fop.layoutmgr.TraitSetter;
 import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition;
+import org.apache.fop.util.BreakUtil;
 
 /**
  * Layout manager for table contents, particularly managing the creation of combined element lists.
@@ -106,7 +103,7 @@
     ColumnSetup getColumns() {
         return getTableLM().getColumns();
     }
-    
+
     /** @return the net header height */
     protected int getHeaderNetHeight() {
         return this.headerNetHeight;
@@ -207,52 +204,57 @@
     private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter, 
             LayoutContext context, int alignment, int bodyType) {
         LinkedList returnList = new LinkedList();
-        EffRow[] rowGroup = null;
-        int breakBetween = Constants.EN_AUTO;
-        while ((rowGroup = iter.getNextRowGroup()) != null) {
+        EffRow[] rowGroup = iter.getNextRowGroup();
+        // TODO homogenize the handling of keeps and breaks
+        context.unsetFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING
+                | LayoutContext.KEEP_WITH_NEXT_PENDING);
+        context.setBreakBefore(Constants.EN_AUTO);
+        context.setBreakAfter(Constants.EN_AUTO);
+        boolean keepWithPrevious = false;
+        int breakBefore = Constants.EN_AUTO;
+        if (rowGroup != null) {
             RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
                     stepper);
-            if (breakBetween == Constants.EN_AUTO) {
-                // TODO improve
-                breakBetween = rowGroupLM.getBreakBefore();
-            }
-            if (breakBetween != Constants.EN_AUTO) {
-                if (returnList.size() > 0) {
-                    BreakElement breakPoss = (BreakElement) returnList.getLast();
-                    breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE);
-                    breakPoss.setBreakClass(breakBetween);
-                } else {
-                    returnList.add(new BreakElement(new Position(tableLM),
-                            0, -KnuthPenalty.INFINITE, breakBetween, context));
+            List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
+            keepWithPrevious = context.isKeepWithPreviousPending();
+            boolean keepBetween = context.isKeepWithNextPending();
+            breakBefore = context.getBreakBefore();
+            int breakBetween = context.getBreakAfter();
+            returnList.addAll(nextRowGroupElems);
+            while ((rowGroup = iter.getNextRowGroup()) != null) {
+                rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper);
+                nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
+                int penaltyValue = 0;
+                keepBetween |= context.isKeepWithPreviousPending();
+                if (keepBetween || tableLM.getTable().mustKeepTogether()) {
+                    penaltyValue = KnuthElement.INFINITE;
                 }
-            }
-            returnList.addAll(rowGroupLM.getNextKnuthElements(context, alignment, bodyType));
-            breakBetween = rowGroupLM.getBreakAfter();
-        }
-        // Break after the table's last row
-        // TODO should eventually be handled at the table level
-        if (breakBetween != Constants.EN_AUTO) {
-            if (returnList.size() > 0 && ((ListElement) returnList.getLast()).isPenalty()) {
-                // May be a glue if the unbroken height is greater than the broken heights
-                BreakElement breakPoss = (BreakElement) returnList.getLast();
-                breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE);
-                breakPoss.setBreakClass(breakBetween);
-            } else {
-                returnList.add(new BreakElement(new Position(tableLM),
-                        0, -KnuthPenalty.INFINITE, breakBetween, context));
-            }
-        }
-        if (returnList.size() > 0) {
-            //Remove the last penalty produced by the combining algorithm (see TableStepper), 
-            //for the last step
-            ListElement last = (ListElement)returnList.getLast();
-            if (last.isPenalty() || last instanceof BreakElement) {
-                if (!last.isForcedBreak()) {
-                    //Only remove if we don't signal a forced break
-                    returnList.removeLast();
+                breakBetween = BreakUtil.compareBreakClasses(breakBetween,
+                        context.getBreakBefore());
+                if (breakBetween != Constants.EN_AUTO) {
+                    penaltyValue = -KnuthElement.INFINITE;
+                }
+                TableHFPenaltyPosition penaltyPos = new TableHFPenaltyPosition(getTableLM());
+                int penaltyLen = 0;
+                if (bodyType == TableRowIterator.BODY) {
+                    if (!getTableLM().getTable().omitHeaderAtBreak()) {
+                        penaltyLen += getHeaderNetHeight();
+                        penaltyPos.headerElements = getHeaderElements();
+                    }
+                    if (!getTableLM().getTable().omitFooterAtBreak()) {
+                        penaltyLen += getFooterNetHeight();
+                        penaltyPos.footerElements = getFooterElements();
+                    }
                 }
+                returnList.add(new BreakElement(penaltyPos, 
+                        penaltyLen, penaltyValue, breakBetween, context));
+                returnList.addAll(nextRowGroupElems);
+                breakBetween = context.getBreakAfter();
+                keepBetween = context.isKeepWithNextPending();
             }
         }
+        context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, keepWithPrevious);
+        context.setBreakBefore(breakBefore);
 
         //fox:widow-content-limit
         int widowContentLimit = getTableLM().getTable().getWidowContentLimit().getValue(); 
@@ -287,7 +289,7 @@
         this.usedBPD = 0;
         RowPainter painter = new RowPainter(this, layoutContext);
 
-        List positions = new java.util.ArrayList();
+        List tablePositions = new ArrayList();
         List headerElements = null;
         List footerElements = null;
         Position firstPos = null;
@@ -324,7 +326,7 @@
                 //ignore for now, see special handling below if break is at a penalty
                 //Only if the last position in this part/page us such a position it will be used 
             } else if (pos instanceof TableContentPosition) {
-                positions.add(pos);
+                tablePositions.add(pos);
             } else {
                 if (log.isDebugEnabled()) {
                     log.debug("Ignoring position: " + pos);
@@ -353,21 +355,23 @@
         if (headerElements != null) {
             //header positions for the last part are the second-to-last element and need to
             //be handled first before all other TableContentPositions
-            PositionIterator nestedIter = new KnuthPossPosIter(headerElements);
-            iterateAndPaintPositions(nestedIter, painter, false);
+            addHeaderFooterAreas(headerElements, tableLM.getTable().getTableHeader(), painter,
+                    false);
         }
         
-        //Iterate over all steps
-        Iterator posIter = positions.iterator();
-        painter.startBody();
-        // Here we are sure that posIter iterates only over TableContentPosition instances
-        iterateAndPaintPositions(posIter, painter, footerElements == null);
-        painter.endBody();
+        if (tablePositions.isEmpty()) {
+            // TODO make sure this actually never happens
+            log.error("tablePositions empty."
+                    + " Please send your FO file to fop-users@xmlgraphics.apache.org");
+        } else {
+            // Here we are sure that posIter iterates only over TableContentPosition instances
+            addBodyAreas(tablePositions.iterator(), painter, footerElements == null);
+        }
 
         if (footerElements != null) {
             //Positions for footers are simply added at the end
-            PositionIterator nestedIter = new KnuthPossPosIter(footerElements);
-            iterateAndPaintPositions(nestedIter, painter, true);
+            addHeaderFooterAreas(footerElements, tableLM.getTable().getTableFooter(), painter,
+                    true);
         }
         
         this.usedBPD += painter.getAccumulatedBPD();
@@ -378,105 +382,73 @@
         }
     }
 
-    /**
-     * Iterates over a part of the table (header, footer, body) and paints the related
-     * elements.
-     * 
-     * @param iterator iterator over Position elements. Those positions correspond to the
-     * elements of the table present on the current page
-     * @param painter
-     * @param lastOnPage true if the corresponding part will be the last on the page
-     * (either body or footer, obviously)
-     */
-    private void iterateAndPaintPositions(Iterator iterator, RowPainter painter,
+    private void addHeaderFooterAreas(List elements, TableBody part, RowPainter painter,
             boolean lastOnPage) {
-        List lst = new ArrayList();
-        boolean firstPos = false;
-        TableBody body = null;
-        while (iterator.hasNext()) {
-            Position pos = (Position)iterator.next();
+        List lst = new ArrayList(elements.size());
+        for (Iterator iter = new KnuthPossPosIter(elements); iter.hasNext();) {
+            Position pos = (Position) iter.next();
+            /*
+             * Unlike for the body the Positions associated to the glues generated by
+             * TableStepper haven't been removed yet.
+             */
             if (pos instanceof TableContentPosition) {
-                TableContentPosition tcpos = (TableContentPosition)pos;
-                lst.add(tcpos);
-                CellPart part = (CellPart)tcpos.cellParts.get(0);
-                if (body == null) {
-                    body = part.pgu.getBody();
-                }
-                if (tcpos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP)
-                        && tcpos.row.getFlag(EffRow.FIRST_IN_PART)) {
-                    firstPos = true;
-
-                }
-                if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP) 
-                        && tcpos.row.getFlag(EffRow.LAST_IN_PART)) {
-                    log.trace("LAST_IN_ROWGROUP + LAST_IN_PART");
-                    handleMarkersAndPositions(lst, body, firstPos, true, painter);
-                    //reset
-                    firstPos = false;
-                    body = null;
-                    lst.clear();
-                }
+                lst.add((TableContentPosition) pos);
             }
         }
-        if (body != null) {
-            // Entering this block means that the end of the current table-part hasn't
-            // been reached (otherwise it would have been caught by the test above). So
-            // lastPos is necessarily false
-            handleMarkersAndPositions(lst, body, firstPos, false, painter);
-        }
-        painter.addAreasAndFlushRow(true, lastOnPage);
-    }
-
-    private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,
-            boolean lastPos, RowPainter painter) {
-        getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 
-                true, firstPos, lastPos);
-        int size = positions.size();
-        for (int i = 0; i < size; i++) {
-            painter.handleTableContentPosition((TableContentPosition)positions.get(i));
-        }
-        getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 
-                false, firstPos, lastPos);
+        addTablePartAreas(lst, painter, part, true, true, true, lastOnPage);
     }
 
     /**
-     * Get the area for a row for background.
-     * @param row the table-row object or null
-     * @return the row area or null if there's no background to paint
+     * Iterates over the positions corresponding to the table's body (which may contain
+     * several table-body elements!) and adds the corresponding areas.
+     * 
+     * @param iterator iterator over TableContentPosition elements. Those positions
+     * correspond to the elements of the body present on the current page
+     * @param painter
+     * @param lastOnPage true if the table has no footer (then the last line of the table
+     * that will be present on the page belongs to the body)
      */
-    Block getRowArea(TableRow row) {
-        if (row == null || !row.getCommonBorderPaddingBackground().hasBackground()) {
-            return null;
-        } else {
-            Block block = new Block();
-            block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
-            block.setPositioning(Block.ABSOLUTE);
-            return block;
-        }
+    private void addBodyAreas(Iterator iterator, RowPainter painter,
+            boolean lastOnPage) {
+        painter.startBody();
+        List lst = new ArrayList();
+        TableContentPosition pos = (TableContentPosition) iterator.next();
+        boolean isFirstPos = pos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP)
+                && pos.getRow().getFlag(EffRow.FIRST_IN_PART);
+        TableBody body = pos.getTableBody();
+        lst.add(pos);
+        while (iterator.hasNext()) {
+            pos = (TableContentPosition) iterator.next();
+            if (pos.getTableBody() != body) {
+                addTablePartAreas(lst, painter, body, isFirstPos, true, false, false);
+                isFirstPos = true;
+                lst.clear();
+                body = pos.getTableBody();
+            }
+            lst.add(pos);
+        }
+        boolean isLastPos = pos.getFlag(TableContentPosition.LAST_IN_ROWGROUP)
+                && pos.getRow().getFlag(EffRow.LAST_IN_PART);
+        addTablePartAreas(lst, painter, body, isFirstPos, isLastPos, true, lastOnPage);
+        painter.endBody();
     }
 
     /**
-     * Adds the area for the row background if any.
-     * @param row row for which to generate the background
-     * @param bpd block-progression-dimension of the row
-     * @param ipd inline-progression-dimension of the row
-     * @param yoffset Y offset at which to paint
+     * Adds the areas corresponding to a single fo:table-header/footer/body element.
      */
-    void addRowBackgroundArea(TableRow row, int bpd, int ipd, int yoffset) {
-        //Add row background if any
-        Block rowBackground = getRowArea(row);
-        if (rowBackground != null) {
-            rowBackground.setBPD(bpd);
-            rowBackground.setIPD(ipd);
-            rowBackground.setXOffset(this.startXOffset);
-            rowBackground.setYOffset(yoffset);
-            getTableLM().addChildArea(rowBackground);
-            TraitSetter.addBackground(rowBackground, 
-                    row.getCommonBorderPaddingBackground(), getTableLM());
+    private void addTablePartAreas(List positions, RowPainter painter, TableBody body,
+            boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) {
+        getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 
+                true, isFirstPos, isLastPos);
+        painter.startTablePart(body);
+        for (Iterator iter = positions.iterator(); iter.hasNext();) {
+            painter.handleTableContentPosition((TableContentPosition) iter.next());
         }
+        getTableLM().getCurrentPV().addMarkers(body.getMarkers(), 
+                false, isFirstPos, isLastPos);
+        painter.endTablePart(lastInBody, lastOnPage);
     }
-    
-    
+
     /**
      * Sets the overall starting x-offset. Used for proper placement of cells.
      * @param startXOffset starting x-offset (table's start-indent)

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Mar  6 05:33:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java Thu Mar  6 05:33:44 2008
@@ -22,6 +22,7 @@
 import java.util.List;
 
 import org.apache.fop.fo.flow.table.EffRow;
+import org.apache.fop.fo.flow.table.TableBody;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.Position;
 
@@ -39,10 +40,12 @@
     /** the list of CellParts making up this position */
     protected List cellParts;
     /** effective row this position belongs to */
-    protected EffRow row;
+    private EffRow row;
     /** flags for the position */
     protected int flags;
 
+    private EffRow newPageRow;
+
     /**
      * Creates a new TableContentPosition.
      * @param lm applicable layout manager
@@ -54,6 +57,31 @@
         super(lm);
         this.cellParts = cellParts;
         this.row = row;
+        this.newPageRow = row;
+    }
+
+    /**
+     * Sets the row corresponding to this position if it starts a new page. In which case,
+     * if the delay mechanism is on, this is the delayed row that starts the page, and not
+     * the current row being extended.
+     * 
+     * @param newPageRow the row that will start the page if this position is the first
+     * one on that page
+     */
+    void setNewPageRow(EffRow newPageRow) {
+        this.newPageRow = newPageRow;
+    }
+
+    EffRow getNewPageRow() {
+        return newPageRow;
+    }
+
+    EffRow getRow() {
+        return row;
+    }
+
+    TableBody getTableBody() {
+        return ((CellPart) cellParts.get(0)).pgu.getTableBody();
     }
 
     /**

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableHFPenaltyPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableHeaderFooterPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java Thu Mar  6 05:33:44 2008
@@ -19,31 +19,34 @@
 
 package org.apache.fop.layoutmgr.table;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+import org.apache.fop.datatypes.LengthBase;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableColumn;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
+import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.ConditionalElementListener;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthGlue;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.ListElement;
-import org.apache.fop.layoutmgr.NonLeafPosition;
 import org.apache.fop.layoutmgr.PositionIterator;
-import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.RelSide;
 import org.apache.fop.layoutmgr.TraitSetter;
-import org.apache.fop.area.Area;
-import org.apache.fop.area.Block;
 import org.apache.fop.traits.MinOptMax;
 import org.apache.fop.traits.SpaceVal;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import org.apache.fop.datatypes.LengthBase;
-import org.apache.fop.fo.FONode;
-import org.apache.fop.fo.FObj;
+import org.apache.fop.util.BreakUtil;
 
 /**
  * LayoutManager for a table FO.
@@ -78,7 +81,27 @@
     
     private int halfBorderSeparationBPD;
     private int halfBorderSeparationIPD;
-    
+
+    /** See {@link TableLayoutManager#registerColumnBackgroundArea(TableColumn, Block, int)}. */
+    private List columnBackgroundAreas;
+
+    /**
+     * Temporary holder of column background informations for a table-cell's area.
+     * 
+     * @see TableLayoutManager#registerColumnBackgroundArea(TableColumn, Block, int)
+     */
+    private static final class ColumnBackgroundInfo {
+        private TableColumn column;
+        private Block backgroundArea;
+        private int xShift;
+
+        private ColumnBackgroundInfo(TableColumn column, Block backgroundArea, int xShift) {
+            this.column = column;
+            this.backgroundArea = backgroundArea;
+            this.xShift = xShift;
+        }
+    }
+
     /**
      * Create a new table layout manager.
      * @param node the table FO
@@ -150,25 +173,11 @@
     public int getHalfBorderSeparationIPD() {
         return halfBorderSeparationIPD;
     }
-    
-    /**
-     * Handles the Knuth elements at the table level: mainly breaks, spaces and borders
-     * before and after the table. The Knuth elements for the table cells are handled by
-     * TableContentLayoutManager.
-     *
-     * @see org.apache.fop.layoutmgr.LayoutManager
-     * @see TableContentLayoutManager#getNextKnuthElements(LayoutContext, int)
-     */
+
+    /** {@inheritDoc} */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         
         LinkedList returnList = new LinkedList();
-        
-        if (!breakBeforeServed) {
-            breakBeforeServed = true;
-            if (addKnuthElementsForBreakBefore(returnList, context)) {
-                return returnList;
-            }
-        }
 
         /*
          * Compute the IPD and adjust it if necessary (overconstrained)
@@ -225,10 +234,7 @@
 
         // Elements for the table-header/footer/body
         LinkedList contentKnuthElements = null;
-        LinkedList contentList = new LinkedList();
-        //Position returnPosition = new NonLeafPosition(this, null);
-        //Body prevLM = null;
-
+        contentLM = new TableContentLayoutManager(this);
         LayoutContext childLC = new LayoutContext(0);
         /*
         childLC.setStackLimit(
@@ -237,46 +243,7 @@
         childLC.setRefIPD(context.getRefIPD());
         childLC.copyPendingMarksFrom(context);
 
-        if (contentLM == null) {
-            contentLM = new TableContentLayoutManager(this);
-        }
         contentKnuthElements = contentLM.getNextKnuthElements(childLC, alignment);
-        if (childLC.isKeepWithNextPending()) {
-            log.debug("TableContentLM signals pending keep-with-next");
-            context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
-        }
-        if (childLC.isKeepWithPreviousPending()) {
-            log.debug("TableContentLM signals pending keep-with-previous");
-            context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
-        }
-
-        // Check if the table's content starts/ends with a forced break
-        // TODO this is hacky and will need to be handled better eventually
-        if (contentKnuthElements.size() > 0) {
-            ListElement element = (ListElement)contentKnuthElements.getFirst();
-            if (element.isForcedBreak()) {
-                // The first row of the table(-body), or (the content of) one of its cells
-                // has a forced break-before
-                int breakBeforeTable = ((Table) fobj).getBreakBefore();
-                if (breakBeforeTable == EN_PAGE
-                        || breakBeforeTable == EN_COLUMN 
-                        || breakBeforeTable == EN_EVEN_PAGE 
-                        || breakBeforeTable == EN_ODD_PAGE) {
-                    // There is already a forced break before the table; remove this one
-                    // to prevent a double break
-                    contentKnuthElements.removeFirst();
-                } else {
-                    element.setPosition(new NonLeafPosition(this, null));
-                }
-            }
-            element = (ListElement)contentKnuthElements.getLast();
-            if (element.isForcedBreak()) {
-                // The last row of the table(-body), or (the content of) one of its cells
-                // has a forced break-after
-                element.setPosition(new NonLeafPosition(this, null));
-            }
-        }
-
         //Set index values on elements coming from the content LM
         Iterator iter = contentKnuthElements.iterator();
         while (iter.hasNext()) {
@@ -284,24 +251,64 @@
             notifyPos(el.getPosition());
         }
         log.debug(contentKnuthElements);
-        contentList.addAll(contentKnuthElements);
-        wrapPositionElements(contentList, returnList);
+        wrapPositionElements(contentKnuthElements, returnList);
+
+        if (mustKeepWithPrevious() || childLC.isKeepWithPreviousPending()) {
+            context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
+        }
+        if (mustKeepWithNext() || childLC.isKeepWithNextPending()) {
+            context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
+        }
+
         if (getTable().isSeparateBorderModel()) {
             addKnuthElementsForBorderPaddingAfter(returnList, true);
         }
         addKnuthElementsForSpaceAfter(returnList, alignment);
-        addKnuthElementsForBreakAfter(returnList, context);
-        if (mustKeepWithNext()) {
-            context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
+
+        //addKnuthElementsForBreakBefore(returnList, context);
+        int breakBefore = BreakUtil.compareBreakClasses(getTable().getBreakBefore(),
+                childLC.getBreakBefore());
+        if (breakBefore != Constants.EN_AUTO) {
+            returnList.addFirst(new BreakElement(getAuxiliaryPosition(), 
+                    0, -KnuthElement.INFINITE, breakBefore, context));
         }
-        if (mustKeepWithPrevious()) {
-            context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
+
+        //addKnuthElementsForBreakAfter(returnList, context);
+        int breakAfter = BreakUtil.compareBreakClasses(getTable().getBreakAfter(),
+                childLC.getBreakAfter());
+        if (breakAfter != Constants.EN_AUTO) {
+            returnList.add(new BreakElement(getAuxiliaryPosition(), 
+                    0, -KnuthElement.INFINITE, breakAfter, context));
         }
+
         setFinished(true);
         resetSpaces();
         return returnList;
     }
-    
+
+    /**
+     * Registers the given area, that will be used to render the part of column background
+     * covered by a table-cell. If percentages are used to place the background image, the
+     * final bpd of the (fraction of) table that will be rendered on the current page must
+     * be known. The traits can't then be set when the areas for the cell are created
+     * since at that moment this bpd is yet unknown. So they will instead be set in
+     * TableLM's {@link #addAreas(PositionIterator, LayoutContext)} method.
+     * 
+     * @param column the table-column element from which the cell gets background
+     * informations
+     * @param backgroundArea the block of the cell's dimensions that will hold the column
+     * background
+     * @param xShift additional amount by which the image must be shifted to be correctly
+     * placed (to counterbalance the cell's start border)
+     */
+    void registerColumnBackgroundArea(TableColumn column, Block backgroundArea, int xShift) {
+        addBackgroundArea(backgroundArea);
+        if (columnBackgroundAreas == null) {
+            columnBackgroundAreas = new ArrayList();
+        }
+        columnBackgroundAreas.add(new ColumnBackgroundInfo(column, backgroundArea, xShift));
+    }
+
     /**
      * The table area is a reference area that contains areas for
      * columns, bodies, rows and the contents are in cells.
@@ -336,6 +343,17 @@
 
         curBlockArea.setBPD(tableHeight);
 
+        if (columnBackgroundAreas != null) {
+            for (Iterator iter = columnBackgroundAreas.iterator(); iter.hasNext();) {
+                ColumnBackgroundInfo b = (ColumnBackgroundInfo) iter.next();
+                TraitSetter.addBackground(b.backgroundArea,
+                        b.column.getCommonBorderPaddingBackground(), this,
+                        b.xShift, -b.backgroundArea.getYOffset(),
+                        b.column.getColumnWidth().getValue(this), tableHeight);
+            }
+            columnBackgroundAreas.clear();
+        }
+
         if (getTable().isSeparateBorderModel()) {
             TraitSetter.addBorders(curBlockArea, 
                     getTable().getCommonBorderPaddingBackground(), 
@@ -402,6 +420,15 @@
         if (curBlockArea != null) {
             curBlockArea.addBlock((Block) childArea);
         }
+    }
+
+    /**
+     * Adds the given area to this layout manager's area, without updating the used bpd.
+     * 
+     * @param background an area
+     */
+    void addBackgroundArea(Block background) {
+        curBlockArea.addChildArea(background);
     }
 
     /** {@inheritDoc} */

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Mar  6 05:33:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Mar  6 05:33:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableStepper.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableStepper.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableStepper.java Thu Mar  6 05:33:44 2008
@@ -26,17 +26,16 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.FONode;
 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.TableRow;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthGlue;
 import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.util.BreakUtil;
 
 /**
  * This class processes row groups to create combined element lists for tables.
@@ -52,51 +51,69 @@
     /** Number of columns in the row group. */
     private int columnCount;
     private int totalHeight;
-    private int previousRowsLength = 0;
+    private int previousRowsLength;
     private int activeRowIndex;
-    private boolean rowBacktrackForLastStep;
-    private boolean skippedStep;
 
+    private boolean rowFinished;
+
+    /** Cells spanning the current row. */
     private List activeCells = new LinkedList();
 
+    /** Cells that will start the next row. */
+    private List nextActiveCells = new LinkedList();
+
     /**
-     * Main constructor
-     * @param tclm The parent TableContentLayoutManager
+     * True if the next row is being delayed, that is, if cells spanning the current and
+     * the next row have steps smaller than the next row's first step. In this case the
+     * next row may be extended to offer additional break possibilities.
      */
-    public TableStepper(TableContentLayoutManager tclm) {
-        this.tclm = tclm;
-        this.columnCount = tclm.getTableLM().getTable().getNumberOfColumns();
-    }
+    private boolean delayingNextRow;
 
     /**
-     * Initializes the fields of this instance to handle a new row group.
+     * The first step for a row. This is the minimal step necessary to include some
+     * content from all the cells starting the row.
+     */
+    private int rowFirstStep;
+
+    /**
+     * Flag used to produce an infinite penalty if the height of the current row is
+     * smaller than the first step for that row (may happen with row-spanning cells).
      * 
-     * @param rowGroup the new row group to handle
+     * @see #considerRowLastStep(int)
      */
-    private void setup(EffRow[] rowGroup) {
-        this.rowGroup = rowGroup;
-        this.activeRowIndex = 0;
-        this.previousRowsLength = 0;
-    }
+    private boolean rowHeightSmallerThanFirstStep;
 
     /**
-     * Returns the row currently being processed.
-     *
-     * @return the row currently being processed
+     * The class of the next break. One of {@link Constants#EN_AUTO},
+     * {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
+     * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}. Defaults to
+     * EN_AUTO.
      */
-    private EffRow getActiveRow() {
-        return rowGroup[activeRowIndex];
+    private int nextBreakClass;
+
+    /**
+     * Main constructor
+     * @param tclm The parent TableContentLayoutManager
+     */
+    public TableStepper(TableContentLayoutManager tclm) {
+        this.tclm = tclm;
+        this.columnCount = tclm.getTableLM().getTable().getNumberOfColumns();
     }
 
     /**
-     * Returns the grid unit at the given column number on the active row.
-     *
-     * @param column column number of the grid unit to get
-     * @return the corresponding grid unit (may be null)
-     * {@inheritDoc}
+     * Initializes the fields of this instance to handle a new row group.
+     * 
+     * @param rows the new row group to handle
      */
-    private GridUnit getActiveGridUnit(int column) {
-        return getActiveRow().safelyGetGridUnit(column);
+    private void setup(EffRow[] rows) {
+        rowGroup = rows;
+        previousRowsLength = 0;
+        activeRowIndex = 0;
+        activeCells.clear();
+        nextActiveCells.clear();
+        delayingNextRow = false;
+        rowFirstStep = 0;
+        rowHeightSmallerThanFirstStep = false;
     }
 
     private void calcTotalHeight() {
@@ -111,30 +128,34 @@
 
     private int getMaxRemainingHeight() {
         int maxW = 0;
-        if (!rowBacktrackForLastStep) {
-            for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
-                maxW = Math.max(maxW,
-                        ((ActiveCell) iter.next()).getRemainingHeight(activeRowIndex));
+        for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
+            ActiveCell activeCell = (ActiveCell) iter.next();
+            int remain = activeCell.getRemainingLength();
+            PrimaryGridUnit pgu = activeCell.getPrimaryGridUnit();
+            for (int i = activeRowIndex + 1; i < pgu.getRowIndex() - rowGroup[0].getIndex()
+                    + pgu.getCell().getNumberRowsSpanned(); i++) {
+                remain -= rowGroup[i].getHeight().opt;
             }
+            maxW = Math.max(maxW, remain);
         }
-        for (int i = activeRowIndex + (rowBacktrackForLastStep ? 0 : 1); i < rowGroup.length; i++) {
+        for (int i = activeRowIndex + 1; i < rowGroup.length; i++) {
             maxW += rowGroup[i].getHeight().opt;
         }
-        log.debug("maxRemainingHeight=" + maxW);
         return maxW;
     }
 
     /**
-     * Initializes the informations relative to the Knuth elements, to handle a new row in
-     * the current row group.
+     * Creates ActiveCell instances for cells starting on the row at the given index.
+     * 
+     * @param activeCellList the list that will hold the active cells
+     * @param rowIndex the index of the row from which cells must be activated
      */
-    private void initializeElementLists() {
-        log.trace("Entering initializeElementLists()");
-        EffRow row = getActiveRow();
+    private void activateCells(List activeCellList, int rowIndex) {
+        EffRow row = rowGroup[rowIndex];
         for (int i = 0; i < columnCount; i++) {
-            GridUnit gu = getActiveGridUnit(i);
-            if (gu != null && !gu.isEmpty() && gu.isPrimary()) {
-                activeCells.add(new ActiveCell((PrimaryGridUnit) gu, row, activeRowIndex,
+            GridUnit gu = row.getGridUnit(i);
+            if (!gu.isEmpty() && gu.isPrimary()) {
+                activeCellList.add(new ActiveCell((PrimaryGridUnit) gu, row, rowIndex,
                         previousRowsLength, getTableLM()));
             }
         }
@@ -143,61 +164,55 @@
     /**
      * Creates the combined element list for a row group.
      * @param context Active LayoutContext
-     * @param rowGroup the row group
+     * @param rows the row group
      * @param bodyType Indicates what type of body is processed (body, header or footer)
      * @return the combined element list
      */
-    public LinkedList getCombinedKnuthElementsForRowGroup(LayoutContext context, EffRow[] rowGroup,
+    public LinkedList getCombinedKnuthElementsForRowGroup(LayoutContext context, EffRow[] rows,
             int bodyType) {
-        setup(rowGroup);
-        initializeElementLists();
+        setup(rows);
+        activateCells(activeCells, 0);
         calcTotalHeight();
 
-        boolean signalKeepWithNext = false;
-        int laststep = 0;
-        int step;
         int cumulateLength = 0; // Length of the content accumulated before the break
         TableContentPosition lastTCPos = null;
         LinkedList returnList = new LinkedList();
-        while ((step = getNextStep()) >= 0) {
-            int normalRow = activeRowIndex;
-            int increase = step - laststep;
-            int penaltyOrGlueLen = step + getMaxRemainingHeight() - totalHeight;
-            int boxLen = step - cumulateLength - Math.max(0, penaltyOrGlueLen)/* the penalty, if any */;
+        int laststep = 0;
+        int step = getFirstStep();
+        do {
+            int maxRemainingHeight = getMaxRemainingHeight();
+            int penaltyOrGlueLen = step + maxRemainingHeight - totalHeight;
+            int boxLen = step - cumulateLength - Math.max(0, penaltyOrGlueLen)/* penalty, if any */;
             cumulateLength += boxLen + Math.max(0, -penaltyOrGlueLen)/* the glue, if any */;
 
-            boolean forcedBreak = false;
-            int breakClass = -1;
+            if (log.isDebugEnabled()) {
+                log.debug("Next step: " + step + " (+" + (step - laststep) + ")");
+                log.debug("           max remaining height: " + maxRemainingHeight);
+                if (penaltyOrGlueLen >= 0) {
+                    log.debug("           box = " + boxLen + " penalty = " + penaltyOrGlueLen);
+                } else {
+                    log.debug("           box = " + boxLen + " glue = " + (-penaltyOrGlueLen));
+                }
+            }
+
             //Put all involved grid units into a list
             List cellParts = new java.util.ArrayList(columnCount);
             for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
                 ActiveCell activeCell = (ActiveCell) iter.next();
                 CellPart part = activeCell.createCellPart();
                 cellParts.add(part);
-                if (activeCell.contributesContent()) {
-                    forcedBreak = activeCell.isLastForcedBreak();
-                    if (forcedBreak) {
-                        breakClass = activeCell.getLastBreakClass();
-                    }
-                }
-                if (returnList.size() == 0 && part.isFirstPart()
-                        && part.mustKeepWithPrevious()) {
-                    context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
-                }
             }
-            //log.debug(">>> guPARTS: " + cellParts);
 
             //Create elements for step
             TableContentPosition tcpos = new TableContentPosition(getTableLM(),
-                    cellParts, rowGroup[normalRow]);
+                    cellParts, rowGroup[activeRowIndex]);
+            if (delayingNextRow) {
+                tcpos.setNewPageRow(rowGroup[activeRowIndex + 1]);
+            }
             if (returnList.size() == 0) {
                 tcpos.setFlag(TableContentPosition.FIRST_IN_ROWGROUP, true);
             }
             lastTCPos = tcpos;
-            if (log.isDebugEnabled()) {
-                log.debug(" - backtrack=" + rowBacktrackForLastStep
-                        + " - row=" + activeRowIndex + " - " + tcpos);
-            }
             returnList.add(new KnuthBox(boxLen, tcpos, false));
 
             int effPenaltyLen = Math.max(0, penaltyOrGlueLen);
@@ -214,77 +229,126 @@
             }
 
             int p = 0;
-            boolean allCellsHaveContributed = true;
-            signalKeepWithNext = false;
+            boolean keepWithNext = false;
             for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
                 ActiveCell activeCell = (ActiveCell) iter.next();
-                allCellsHaveContributed &= activeCell.hasStarted();
-                signalKeepWithNext |= activeCell.keepWithNextSignal();
+                keepWithNext |= activeCell.keepWithNextSignal();
             }
-            if (!allCellsHaveContributed) {
-                //Not all cells have contributed to a newly started row. The penalty here is
-                //used to avoid breaks resulting in badly broken tables.
-                //See also: http://marc.theaimsgroup.com/?t=112248999600005&r=1&w=2
-                p = 900; //KnuthPenalty.INFINITE; //TODO Arbitrary value. Please refine.
-            }
-            if (signalKeepWithNext || getTableLM().mustKeepTogether()) {
-                p = KnuthPenalty.INFINITE;
-            }
-            if (skippedStep) {
+            if (keepWithNext || getTableLM().mustKeepTogether()) {
                 p = KnuthPenalty.INFINITE;
-                //Need to avoid breaking because borders and/or paddding from other columns would
-                //not fit in the available space (see getNextStep())
             }
-            if (forcedBreak) {
-                if (skippedStep) {
-                    log.error("This is a conflict situation. The output may be wrong."
-                            + " Please send your FO file to fop-dev@xmlgraphics.apache.org!");
+            if (!rowFinished) {
+                if (rowGroup[activeRowIndex].mustKeepTogether()) {
+                    p = KnuthPenalty.INFINITE;
+                }
+            } else if (activeRowIndex < rowGroup.length - 1) {
+                if (rowGroup[activeRowIndex].mustKeepWithNext()
+                        || rowGroup[activeRowIndex + 1].mustKeepWithPrevious()) {
+                    p = KnuthPenalty.INFINITE;
                 }
+                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                        rowGroup[activeRowIndex].getBreakAfter());
+                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                        rowGroup[activeRowIndex + 1].getBreakBefore());
+            }
+            if (nextBreakClass != Constants.EN_AUTO) {
+                log.trace("Forced break encountered");
                 p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
             }
-            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context));
+            if (rowHeightSmallerThanFirstStep) {
+                rowHeightSmallerThanFirstStep = false;
+                p = KnuthPenalty.INFINITE;
+            }
+            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, nextBreakClass, context));
             if (penaltyOrGlueLen < 0) {
                 returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true));
             }
 
-            if (log.isDebugEnabled()) {
-                log.debug("step=" + step + " (+" + increase + ")"
-                        + " box=" + boxLen
-                        + " penalty=" + penaltyOrGlueLen
-                        + " effPenalty=" + effPenaltyLen);
-            }
-
             laststep = step;
-        }
-        if (signalKeepWithNext) {
-            //Last step signalled a keep-with-next. Since the last penalty will be removed,
-            //we have to signal the still pending last keep-with-next using the LayoutContext.
-            context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
-        }
-        if (lastTCPos != null) {
+            step = getNextStep();
+        } while (step >= 0);
+        if (!returnList.isEmpty()) {
             lastTCPos.setFlag(TableContentPosition.LAST_IN_ROWGROUP, true);
+            // It's not up to TableStepper to decide whether there can/must be a break
+            // after the row group or not, but to ancestor stacking elements
+            assert returnList.getLast() instanceof BreakElement;
+            returnList.removeLast();
         }
         return returnList;
     }
 
     /**
-     * Finds the smallest increment leading to the next legal break inside the row-group.
+     * Returns the first step for the current row group.
      * 
-     * @return the size of the increment, -1 if no next step is available (end of row-group reached)
+     * @return the first step for the current row group
+     */
+    private int getFirstStep() {
+        computeRowFirstStep(activeCells);
+        signalRowFirstStep();
+        int minStep = considerRowLastStep(rowFirstStep);
+        signalNextStep(minStep);
+        return minStep;
+    }
+
+    /**
+     * Returns the next break possibility.
+     * 
+     * @return the next step
      */
     private int getNextStep() {
-        log.trace("Entering getNextStep");
-        //Check for forced break conditions
-        /*
-        if (isBreakCondition()) {
-            return -1;
-        }*/
+        if (rowFinished) {
+            if (activeRowIndex == rowGroup.length - 1) {
+                // The row group is finished, no next step
+                return -1;
+            }
+            rowFinished = false;
+            removeCellsEndingOnCurrentRow();
+            log.trace("Delaying next row");
+            delayingNextRow = true;
+        }
+        if (delayingNextRow) {
+            int minStep = computeMinStep();
+            if (minStep < 0 || minStep >= rowFirstStep
+                    || minStep > rowGroup[activeRowIndex].getExplicitHeight().max) {
+                if (log.isTraceEnabled()) {
+                    log.trace("Step = " + minStep);
+                }
+                delayingNextRow = false;
+                minStep = rowFirstStep;
+                switchToNextRow();
+                signalRowFirstStep();
+                minStep = considerRowLastStep(minStep);
+            }
+            signalNextStep(minStep);
+            return minStep;
+        } else {
+            int minStep = computeMinStep();
+            minStep = considerRowLastStep(minStep);
+            signalNextStep(minStep);
+            return minStep;
+        }
+    }
 
-        //set starting points
-        goToNextRowIfCurrentFinished();
+    /**
+     * Computes the minimal necessary step to make the next row fit. That is, so such as
+     * cell on the next row can contribute some content.
+     * 
+     * @param cells the cells occupying the next row (may include cells starting on
+     * previous rows and spanning over this one)
+     */
+    private void computeRowFirstStep(List cells) {
+        for (Iterator iter = cells.iterator(); iter.hasNext();) {
+            ActiveCell activeCell = (ActiveCell) iter.next();
+            rowFirstStep = Math.max(rowFirstStep, activeCell.getFirstStep());
+        }
+    }
 
-        //Get next possible sequence for each cell
-        //Determine smallest possible step
+    /**
+     * Computes the next minimal step.
+     * 
+     * @return the minimal step from the active cells, &lt; 0 if there is no such step
+     */
+    private int computeMinStep() {
         int minStep = Integer.MAX_VALUE;
         boolean stepFound = false;
         for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
@@ -295,78 +359,139 @@
                 minStep = Math.min(minStep, nextStep);
             }
         }
-        if (!stepFound) {
+        if (stepFound) {
+            return minStep;
+        } else {
             return -1;
         }
+    }
 
+    /**
+     * Signals the first step to the active cells, to allow them to add more content to
+     * the step if possible.
+     * 
+     * @see ActiveCell#signalRowFirstStep(int)
+     */
+    private void signalRowFirstStep() {
+        for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
+            ActiveCell activeCell = (ActiveCell) iter.next();
+            activeCell.signalRowFirstStep(rowFirstStep);
+        }
+    }
 
-        //Reset bigger-than-minimum sequences
-        //See http://people.apache.org/~jeremias/fop/NextStepAlgoNotes.pdf
-        rowBacktrackForLastStep = false;
-        skippedStep = false;
+    /**
+     * Signals the next selected step to the active cells.
+     *  
+     * @param step the next step
+     */
+    private void signalNextStep(int step) {
+        nextBreakClass = Constants.EN_AUTO;
         for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
             ActiveCell activeCell = (ActiveCell) iter.next();
-            if (activeCell.signalMinStep(minStep)) {
-                if (activeRowIndex == 0) {
-                    log.debug("  First row. Skip this step.");
-                    skippedStep = true;
-                } else {
-                    log.debug("  row-span situation: backtracking to last row");
-                    //Stay on the previous row for another step because borders and padding on 
-                    //columns may make their contribution to the step bigger than the addition
-                    //of the next element for this step would make the step to grow.
-                    rowBacktrackForLastStep = true;
+            nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                    activeCell.signalNextStep(step));
+        }
+    }
+
+    /**
+     * Determines if the given step will finish the current row, and if so switch to the
+     * last step for this row.
+     * <p>If the row is finished then the after borders for the cell may change (their
+     * conditionalities no longer apply for the cells ending on the current row). Thus the
+     * final step may grow with respect to the given one.</p>
+     * <p>In more rare occasions, the given step may correspond to the first step of a
+     * row-spanning cell, and may be greater than the height of the current row (consider,
+     * for example, an unbreakable cell spanning three rows). In such a case the returned
+     * step will correspond to the row height and a flag will be set to produce an
+     * infinite penalty for this step. This will prevent the breaking algorithm from
+     * choosing this break, but still allow to create the appropriate TableContentPosition
+     * for the cells ending on the current row.</p>
+     * 
+     * @param step the next step
+     * @return the updated step if any
+     */
+    private int considerRowLastStep(int step) {
+        rowFinished = true;
+        for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
+            ActiveCell activeCell = (ActiveCell) iter.next();
+            if (activeCell.endsOnRow(activeRowIndex)) {
+                rowFinished &= activeCell.finishes(step);
+            }
+        }
+        if (rowFinished) {
+            if (log.isTraceEnabled()) {
+                log.trace("Step = " + step);
+                log.trace("Row finished, computing last step");
+            }
+            int maxStep = 0;
+            for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
+                ActiveCell activeCell = (ActiveCell) iter.next();
+                if (activeCell.endsOnRow(activeRowIndex)) {
+                    maxStep = Math.max(maxStep, activeCell.getLastStep());
                 }
             }
+            if (log.isTraceEnabled()) {
+                log.trace("Max step: " + maxStep);
+            }
+            for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
+                ActiveCell activeCell = (ActiveCell) iter.next();
+                activeCell.endRow(activeRowIndex);                        
+                if (!activeCell.endsOnRow(activeRowIndex)) {
+                    activeCell.signalRowLastStep(maxStep);
+                }
+            }
+            if (maxStep < step) {
+                log.trace("Row height smaller than first step, produced penalty will be infinite");
+                rowHeightSmallerThanFirstStep = true;
+            }
+            step = maxStep;
+            prepareNextRow();
         }
+        return step;
+    }
 
-        return minStep;
+    /**
+     * Pre-activates the cells that will start the next row, and computes the first step
+     * for that row.
+     */
+    private void prepareNextRow() {
+        if (activeRowIndex < rowGroup.length - 1) {
+            previousRowsLength += rowGroup[activeRowIndex].getHeight().opt;
+            activateCells(nextActiveCells, activeRowIndex + 1);
+            if (log.isTraceEnabled()) {
+                log.trace("Computing first step for row " + (activeRowIndex + 2));
+            }
+            computeRowFirstStep(nextActiveCells);
+            if (log.isTraceEnabled()) {
+                log.trace("Next first step = " + rowFirstStep);
+            }
+        }
     }
 
     private void removeCellsEndingOnCurrentRow() {
         for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
             ActiveCell activeCell = (ActiveCell) iter.next();
-            activeCell.endRow(activeRowIndex);
             if (activeCell.endsOnRow(activeRowIndex)) {
                 iter.remove();
             }
         }
     }
 
-    private void goToNextRowIfCurrentFinished() {
-        // We assume that the current grid row is finished. If this is not the case this
-        // boolean will be reset
-        boolean currentGridRowFinished = true;
+    /**
+     * Actually switches to the next row, increasing activeRowIndex and transferring to
+     * activeCells the cells starting on the next row.
+     */
+    private void switchToNextRow() {
+        activeRowIndex++;
+        if (log.isTraceEnabled()) {
+            log.trace("Switching to row " + (activeRowIndex + 1));
+        }
         for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
             ActiveCell activeCell = (ActiveCell) iter.next();
-            if (activeCell.endsOnRow(activeRowIndex)) {
-                currentGridRowFinished &= activeCell.isFinished();
-            }
-        }
-
-        if (currentGridRowFinished) {
-            removeCellsEndingOnCurrentRow();
-            if (activeRowIndex < rowGroup.length - 1) {
-                TableRow rowFO = getActiveRow().getTableRow();
-                if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) {
-                    log.warn(FONode.decorateWithContextInfo(
-                            "break-after ignored on table-row because of row spanning "
-                            + "in progress (See XSL 1.0, 7.19.1)", rowFO));
-                }
-                previousRowsLength += rowGroup[activeRowIndex].getHeight().opt;
-                activeRowIndex++;
-                if (log.isDebugEnabled()) {
-                    log.debug("===> new row: " + activeRowIndex);
-                }
-                initializeElementLists();
-                rowFO = getActiveRow().getTableRow();
-                if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) {
-                    log.warn(FONode.decorateWithContextInfo(
-                            "break-before ignored on table-row because of row spanning "
-                            + "in progress (See XSL 1.0, 7.19.2)", rowFO));
-                }
-            }
+            activeCell.nextRowStarts();
         }
+        activeCells.addAll(nextActiveCells);
+        nextActiveCells.clear();
     }
 
     /** @return the table layout manager */

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Mar  6 05:33:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/AlphaRasterImage.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/AlphaRasterImage.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/AlphaRasterImage.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/AlphaRasterImage.java Thu Mar  6 05:33:44 2008
@@ -22,6 +22,8 @@
 import java.awt.image.DataBuffer;
 import java.awt.image.Raster;
 import java.awt.image.RenderedImage;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
 import java.io.IOException;
 import java.io.OutputStream;
 
@@ -137,18 +139,37 @@
             throw new UnsupportedOperationException(
                     "Expected only one band/component for the alpha channel");
         }
+
+        //...and write the Raster line by line with a reusable buffer
         int dataType = alpha.getDataBuffer().getDataType();
-        if (dataType != DataBuffer.TYPE_BYTE) {
+        if (dataType == DataBuffer.TYPE_BYTE) {
+            byte[] line = new byte[nbands * w];
+            for (int y = 0; y < h; y++) {
+                alpha.getDataElements(0, y, w, 1, line);
+                out.write(line);
+            }
+        } else if (dataType == DataBuffer.TYPE_INT) {
+            //Is there an better way to get a 8bit raster from a TYPE_INT raster?
+            int shift = 24;
+            SampleModel sampleModel = alpha.getSampleModel();
+            if (sampleModel instanceof SinglePixelPackedSampleModel) {
+                SinglePixelPackedSampleModel m = (SinglePixelPackedSampleModel)sampleModel;
+                shift = m.getBitOffsets()[0];
+            }
+            int[] iline = new int[nbands * w];
+            byte[] line = new byte[nbands * w];
+            for (int y = 0; y < h; y++) {
+                alpha.getDataElements(0, y, w, 1, iline);
+                for (int i = 0; i < w; i++) {
+                    line[i] = (byte)(iline[i] >> shift);
+                }
+                out.write(line);
+            }
+        } else {
             throw new UnsupportedOperationException("Unsupported DataBuffer type: "
                     + alpha.getDataBuffer().getClass().getName());
         }
 
-        //...and write the Raster line by line with a reusable buffer
-        byte[] line = new byte[nbands * w];
-        for (int y = 0; y < h; y++) {
-            alpha.getDataElements(0, y, w, 1, line);
-            out.write(line);
-        }
     }
     
     /** {@inheritDoc} */

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFAMode.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFArray.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFArray.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFArray.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFArray.java Thu Mar  6 05:33:44 2008
@@ -69,6 +69,20 @@
     /**
      * Create an array object.
      * @param parent the array's parent if any
+     * @param values the actual array wrapped by this object
+     */
+    public PDFArray(PDFObject parent, double[] values) {
+        /* generic creation of PDF object */
+        super(parent);
+
+        for (int i = 0, c = values.length; i < c; i++) {
+            this.values.add(new Double(values[i]));
+        }
+    }
+
+    /**
+     * Create an array object.
+     * @param parent the array's parent if any
      * @param values the actual values wrapped by this object
      */
     public PDFArray(PDFObject parent, Collection values) {
@@ -133,7 +147,10 @@
      */
     public void add(Object obj) {
         if (obj instanceof PDFObject) {
-            ((PDFObject)obj).setParent(this);
+            PDFObject pdfObj = (PDFObject)obj;
+            if (!pdfObj.hasObjectNumber()) {
+                pdfObj.setParent(this);
+            }
         }
         this.values.add(obj);
     }

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCIDFontDescriptor.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCIDFontDescriptor.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCIDFontDescriptor.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCIDFontDescriptor.java Thu Mar  6 05:33:44 2008
@@ -22,24 +22,14 @@
 // based on work by Takayuki Takeuchi
 
 /**
- * class representing a font descriptor for CID fonts.
+ * Class representing a font descriptor for CID fonts.
  *
  * Font descriptors for CID fonts are specified on page 227 and onwards of the PDF 1.3 spec.
  */
 public class PDFCIDFontDescriptor extends PDFFontDescriptor {
 
     /**
-     * The language for the font
-     */
-    protected String lang;
-
-    /**
-     * The cid set stream
-     */
-    protected PDFStream cidSet;
-
-    /**
-     * create the /FontDescriptor object
+     * Create a /FontDescriptor object.
      *
      * @param basefont the base font name
      * @param fontBBox the bounding box for the described font
@@ -56,31 +46,19 @@
         super(basefont, fontBBox[3], fontBBox[1], capHeight, flags,
               new PDFRectangle(fontBBox), italicAngle, stemV);
 
-        this.lang = lang;
+        put("MissingWidth", new Integer(500));
+        if (lang != null) {
+            put("Lang", lang);
+        }
     }
 
     /**
      * Set the CID set stream.
-     * @param cidSet the pdf stream cotnaining the CID set
+     * @param cidSet the PDF stream containing the CID set
      */
     public void setCIDSet(PDFStream cidSet) {
-        this.cidSet = cidSet;
-    }
-
-    /**
-     * Fill in the pdf data for this font descriptor.
-     * The charset specific dictionary entries are output.
-     * @param p the string buffer to append the data
-     */
-    protected void fillInPDF(StringBuffer p) {
-        p.append("\n/MissingWidth 500\n");
-        if (lang != null) {
-            p.append("\n/Lang /");
-            p.append(lang);
-        }
         if (cidSet != null) {
-            p.append("\n/CIDSet /");
-            p.append(this.cidSet.referencePDF());
+            put("CIDSet", cidSet);
         }
     }
 

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCMap.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCMap.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCMap.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFCMap.java Thu Mar  6 05:33:44 2008
@@ -21,6 +21,8 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.Writer;
 
 /**
  * Class representing the CMap encodings.
@@ -395,15 +397,6 @@
     }
 
     /**
-     * Add the contents of this pdf object to the PDF stream.
-     */
-    public void addContents() {
-        StringBuffer p = new StringBuffer();
-        fillInPDF(p);
-        add(p.toString());
-    }
-
-    /**
      * set the base CMap
      *
      * @param base the name of the base CMap
@@ -422,107 +415,20 @@
     }
 
     /**
-     * Fill in the pdf string for this CMap.
-     *
-     * @param p the string buffer to add the pdf data to
+     * Creates the CMapBuilder that will build the CMap's content.
+     * @param writer a Writer to write the CMap's contents to
+     * @return the newly created CMapBuilder
      */
-    public void fillInPDF(StringBuffer p) {
-        writePreStream(p);
-        writeStreamComments(p);
-        writeCIDInit(p);
-        writeCIDSystemInfo(p);
-        writeVersionTypeName(p);
-        writeCodeSpaceRange(p);
-        writeCIDRange(p);
-        writeBFEntries(p);
-        writeWrapUp(p);
-        writeStreamAfterComments(p);
-        writeUseCMap(p);
-        add(p.toString());
-    }
-
-    protected void writePreStream(StringBuffer p) {
-        // p.append("/Type /CMap\n");
-        // p.append(sysInfo.toPDFString());
-        // p.append("/CMapName /" + name + EOL);
-    }
-
-    protected void writeStreamComments(StringBuffer p) {
-        p.append("%!PS-Adobe-3.0 Resource-CMap\n");
-        p.append("%%DocumentNeededResources: ProcSet (CIDInit)\n");
-        p.append("%%IncludeResource: ProcSet (CIDInit)\n");
-        p.append("%%BeginResource: CMap (" + name + ")\n");
-        p.append("%%EndComments\n");
-    }
-
-    protected void writeCIDInit(StringBuffer p) {
-        p.append("/CIDInit /ProcSet findresource begin\n");
-        p.append("12 dict begin\n");
-        p.append("begincmap\n");
-    }
-
-    protected void writeCIDSystemInfo(StringBuffer p) {
-        p.append("/CIDSystemInfo 3 dict dup begin\n");
-        p.append("  /Registry (Adobe) def\n");
-        p.append("  /Ordering (Identity) def\n");
-        p.append("  /Supplement 0 def\n");
-        p.append("end def\n");
-    }
-
-    protected void writeVersionTypeName(StringBuffer p) {
-        p.append("/CMapVersion 1 def\n");
-        p.append("/CMapType 1 def\n");
-        p.append("/CMapName /" + name + " def\n");
-    }
-
-    protected void writeCodeSpaceRange(StringBuffer p) {
-        p.append("1 begincodespacerange\n");
-        p.append("<0000> <FFFF>\n");
-        p.append("endcodespacerange\n");
-    }
-
-    protected void writeCIDRange(StringBuffer p) {
-        p.append("1 begincidrange\n");
-        p.append("<0000> <FFFF> 0\n");
-        p.append("endcidrange\n");
-    }
-
-    protected void writeBFEntries(StringBuffer p) {
-        // p.append("1 beginbfrange\n");
-        // p.append("<0020> <0100> <0000>\n");
-        // p.append("endbfrange\n");
+    protected CMapBuilder createCMapBuilder(Writer writer) {
+        return new CMapBuilder(writer, this.name);
     }
-
-    protected void writeWrapUp(StringBuffer p) {
-        p.append("endcmap\n");
-        p.append("CMapName currentdict /CMap defineresource pop\n");
-        p.append("end\n");
-        p.append("end\n");
-    }
-
-    protected void writeStreamAfterComments(StringBuffer p) {
-        p.append("%%EndResource\n");
-        p.append("%%EOF\n");
-    }
-
-    protected void writeUseCMap(StringBuffer p) {
-        /*
-         * p.append(" /Type /CMap");
-         * p.append("/CMapName /" + name + EOL);
-         * p.append("/WMode " + wMode + EOL);
-         * if (base != null) {
-         *     p.append("/UseCMap ");
-         * if (base instanceof String) {
-         * p.append("/"+base);
-         * } else {// base instanceof PDFStream
-         * p.append(((PDFStream)base).referencePDF());
-         * }
-         * }
-         */
-    }
-
+    
+    /** {@inheritDoc} */
     protected int output(OutputStream stream) throws IOException {
-        fillInPDF(new StringBuffer());
+        StringWriter writer = new StringWriter();
+        CMapBuilder builder = createCMapBuilder(writer);
+        builder.writeCMap();
+        add(writer.getBuffer().toString()); //TODO Could be optimized by not buffering
         return super.output(stream);
     }
 }

Propchange: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFConformanceException.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFDictionary.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFDictionary.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFDictionary.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFDictionary.java Thu Mar  6 05:33:44 2008
@@ -65,6 +65,12 @@
      * @param value the value
      */
     public void put(String name, Object value) {
+        if (value instanceof PDFObject) {
+            PDFObject pdfObj = (PDFObject)value;
+            if (!pdfObj.hasObjectNumber()) {
+                pdfObj.setParent(this);
+            }
+        }
         if (!entries.containsKey(name)) {
             this.order.add(name);
         }

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFEncoding.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFEncoding.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFEncoding.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFEncoding.java Thu Mar  6 05:33:44 2008
@@ -20,12 +20,11 @@
 package org.apache.fop.pdf;
 
 // Java
-import java.util.List;
-import java.util.Map;
-import java.util.Iterator;
+import java.util.Collections;
+import java.util.Set;
 
 /**
- * class representing an /Encoding object.
+ * Class representing an /Encoding object.
  *
  * A small object expressing the base encoding name and
  * the differences from the base encoding.
@@ -34,90 +33,113 @@
  *
  * Encodings are specified in section 5.5.5 of the PDF 1.4 spec.
  */
-public class PDFEncoding extends PDFObject {
+public class PDFEncoding extends PDFDictionary {
 
-    /**
-     * the name for the standard encoding scheme
-     */
+    /** the name for the standard encoding scheme */
+    public static final String STANDARD_ENCODING = "StandardEncoding";
+    /** the name for the Mac Roman encoding scheme */
     public static final String MAC_ROMAN_ENCODING = "MacRomanEncoding";
-
-    /**
-     * the name for the standard encoding scheme
-     */
+    /** the name for the Mac Export encoding scheme */
     public static final String MAC_EXPERT_ENCODING = "MacExpertEncoding";
-
-    /**
-     * the name for the standard encoding scheme
-     */
+    /** the name for the WinAnsi encoding scheme */
     public static final String WIN_ANSI_ENCODING = "WinAnsiEncoding";
+    /** the name for the PDF document encoding scheme */
+    public static final String PDF_DOC_ENCODING = "PDFDocEncoding";
 
-    /**
-     * the name for the base encoding.
-     * One of the three base encoding scheme names or
-     * the default font's base encoding if null.
-     */
-    protected String basename;
-
-    /**
-     * the differences from the base encoding
-     */
-    protected Map differences;
+    /** the set of predefined encodings that can be assumed present in a PDF viewer */
+    private static final Set PREDEFINED_ENCODINGS;
+    
+    static {
+        Set encodings = new java.util.HashSet();
+        encodings.add(STANDARD_ENCODING);
+        encodings.add(MAC_ROMAN_ENCODING);
+        encodings.add(MAC_EXPERT_ENCODING);
+        encodings.add(WIN_ANSI_ENCODING);
+        encodings.add(PDF_DOC_ENCODING);
+        PREDEFINED_ENCODINGS = Collections.unmodifiableSet(encodings);
+    }
 
     /**
-     * create the /Encoding object
+     * Create a new /Encoding object.
      *
      * @param basename the name of the character encoding schema
      */
     public PDFEncoding(String basename) {
-
-        /* generic creation of PDF object */
         super();
 
-        /* set fields using paramaters */
-        this.basename = basename;
-        this.differences = new java.util.HashMap();
+        put("Type", new PDFName("Encoding"));
+        if (basename != null) {
+            put("BaseEncoding", new PDFName(basename));
+        }
     }
 
     /**
-     * add differences to the encoding
-     *
-     * @param code the first index of the sequence to be changed
-     * @param sequence the sequence of glyph names (as String)
+     * Indicates whether a given encoding is one of the predefined encodings.
+     * @param name the encoding name (ex. "StandardEncoding")
+     * @return true if it is a predefined encoding
+     */
+    public static boolean isPredefinedEncoding(String name) {
+        return PREDEFINED_ENCODINGS.contains(name);
+    }
+    
+    /**
+     * Creates and returns a new DifferencesBuilder instance for constructing the Differences
+     * array.
+     * @return the DifferencesBuilder
      */
-    public void addDifferences(int code, List sequence) {
-        differences.put(new Integer(code), sequence);
+    public DifferencesBuilder createDifferencesBuilder() {
+        return new DifferencesBuilder();
     }
 
     /**
-     * {@inheritDoc}
+     * Sets the Differences value.
+     * @param differences the differences.
+     */
+    public void setDifferences(PDFArray differences) {
+        put("Differences", differences);
+    }
+    
+    /**
+     * Builder class for constructing the Differences array.
      */
-    public String toPDFString() {
-        StringBuffer p = new StringBuffer(128);
-        p.append(getObjectID() 
-            + "<< /Type /Encoding");
-        if ((basename != null) && (!basename.equals(""))) {
-            p.append("\n/BaseEncoding /" + this.basename);
+    public class DifferencesBuilder {
+        
+        private PDFArray differences = new PDFArray();
+        private int currentCode = -1;
+        
+        /**
+         * Start a new difference.
+         * @param code the starting code index inside the encoding
+         * @return this builder instance
+         */
+        public DifferencesBuilder addDifference(int code) {
+            this.currentCode = code;
+            this.differences.add(new Integer(code));
+            return this;
         }
-        if (!differences.isEmpty()) {
-            p.append("\n/Differences [ ");
-            Object code;
-            Iterator codes = differences.keySet().iterator();
-            while (codes.hasNext()) {
-                code = codes.next();
-                p.append(" ");
-                p.append(code);
-                List sequence = (List)differences.get(code);
-                for (int i = 0; i < sequence.size(); i++) {
-                    p.append(" /");
-                    p.append((String)sequence.get(i));
-                }
+        
+        /**
+         * Adds a character name to the current difference.
+         * @param name the character name
+         * @return this builder instance
+         */
+        public DifferencesBuilder addName(String name) {
+            if (this.currentCode < 0) {
+                throw new IllegalStateException("addDifference(int) must be called first");
             }
-            p.append(" ]");
+            this.differences.add(new PDFName(name));
+            return this;
+        }
+        
+        /**
+         * Creates and returns the PDFArray representing the Differences entry.
+         * @return the Differences entry
+         */
+        public PDFArray toPDFArray() {
+            return this.differences;
         }
-        p.append(" >>\nendobj\n");
-        return p.toString();
     }
-
+    
     /*
      * example (p. 214)
      * 25 0 obj

Modified: xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFFactory.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFFactory.java?rev=634267&r1=634266&r2=634267&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFFactory.java (original)
+++ xmlgraphics/fop/branches/Temp_ProcessingFeedback/src/java/org/apache/fop/pdf/PDFFactory.java Thu Mar  6 05:33:44 2008
@@ -43,12 +43,14 @@
 import org.apache.xmlgraphics.xmp.Metadata;
 
 import org.apache.fop.fonts.CIDFont;
+import org.apache.fop.fonts.CodePointMapping;
 import org.apache.fop.fonts.CustomFont;
 import org.apache.fop.fonts.FontDescriptor;
 import org.apache.fop.fonts.FontMetrics;
 import org.apache.fop.fonts.FontType;
 import org.apache.fop.fonts.LazyFont;
 import org.apache.fop.fonts.MultiByteFont;
+import org.apache.fop.fonts.SingleByteFont;
 import org.apache.fop.fonts.Typeface;
 import org.apache.fop.fonts.truetype.FontFileReader;
 import org.apache.fop.fonts.truetype.TTFSubSetFile;
@@ -1182,6 +1184,7 @@
         }
 
         if (descriptor == null) {
+            //Usually Base 14 fonts
             PDFFont font = new PDFFont(fontname, FontType.TYPE1, basefont, encoding);
             getDocument().registerObject(font);
             return font;
@@ -1190,30 +1193,11 @@
 
             PDFFontDescriptor pdfdesc = makeFontDescriptor(descriptor);
 
-            PDFFontNonBase14 font = null;
-            if (fonttype == FontType.TYPE0) {
-                /*
-                 * Temporary commented out - customized CMaps
-                 * isn't needed until /ToUnicode support is added
-                 * PDFCMap cmap = new PDFCMap(++this.objectcount,
-                 * "fop-ucs-H",
-                 * new PDFCIDSystemInfo("Adobe",
-                 * "Identity",
-                 * 0));
-                 * cmap.addContents();
-                 * this.objects.add(cmap);
-                 */
-                font = (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
-                                                            basefont, "Identity-H");
-            } else {
-
-                font = (PDFFontNonBase14)PDFFont.createFont(fontname, fonttype,
-                                                            basefont, encoding);
-            }
+            PDFFont font = null;
+            font = (PDFFont)PDFFont.createFont(fontname, fonttype,
+                                                        basefont, encoding);
             getDocument().registerObject(font);
 
-            font.setDescriptor(pdfdesc);
-
             if (fonttype == FontType.TYPE0) {
                 CIDFont cidMetrics;
                 if (metrics instanceof LazyFont) {
@@ -1233,7 +1217,7 @@
                                    (PDFCIDFontDescriptor)pdfdesc);
                 getDocument().registerObject(cidFont);
 
-                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics, "fop-ucs-H",
+                PDFCMap cmap = new PDFToUnicodeCMap(cidMetrics.getCharsUsed(), "fop-ucs-H",
                     new PDFCIDSystemInfo("Adobe",
                         "Identity",
                         0));
@@ -1241,16 +1225,59 @@
                 ((PDFFontType0)font).setCMAP(cmap);
                 ((PDFFontType0)font).setDescendantFonts(cidFont);
             } else {
-                int firstChar = 0;
-                int lastChar = 255;
-                if (metrics instanceof CustomFont) {
-                    CustomFont cf = (CustomFont)metrics;
-                    firstChar = cf.getFirstChar();
-                    lastChar = cf.getLastChar();
+                PDFFontNonBase14 nonBase14 = (PDFFontNonBase14)font;
+                nonBase14.setDescriptor(pdfdesc);
+
+                SingleByteFont singleByteFont;
+                if (metrics instanceof LazyFont) {
+                    singleByteFont = (SingleByteFont)((LazyFont)metrics).getRealFont();
+                } else {
+                    singleByteFont = (SingleByteFont)metrics;
                 }
-                font.setWidthMetrics(firstChar,
+                int firstChar = singleByteFont.getFirstChar();
+                int lastChar = singleByteFont.getLastChar();
+                nonBase14.setWidthMetrics(firstChar,
                                      lastChar,
                                      makeArray(metrics.getWidths()));
+                
+                //Handle encoding
+                CodePointMapping mapping = singleByteFont.getCodePointMapping();
+                if (PDFEncoding.isPredefinedEncoding(mapping.getName())) {
+                    font.setEncoding(mapping.getName());
+                } else {
+                    CodePointMapping winansi = CodePointMapping.getMapping(
+                            CodePointMapping.WIN_ANSI_ENCODING);
+                    PDFEncoding pdfEncoding = new PDFEncoding(winansi.getName());
+                    PDFEncoding.DifferencesBuilder builder
+                            = pdfEncoding.createDifferencesBuilder();
+                    int start = -1;
+                    String[] winansiNames = winansi.getCharNameMap();
+                    String[] charNameMap = mapping.getCharNameMap();
+                    for (int i = 0; i < 256; i++) {
+                        String wac = winansiNames[i];
+                        String c = charNameMap[i];
+                        if (!wac.equals(c)) {
+                            if (start != i) {
+                                builder.addDifference(i);
+                                start = i;
+                            }
+                            builder.addName(c);
+                            start++;
+                        }
+                    }
+                    pdfEncoding.setDifferences(builder.toPDFArray());
+                    font.setEncoding(pdfEncoding);
+                    
+                    /* JM: What I thought would be a necessity with custom encodings turned out to
+                     * be a bug in Adobe Acrobat 8. The following section just demonstrates how
+                     * to generate a ToUnicode CMap for a Type 1 font. 
+                    PDFCMap cmap = new PDFToUnicodeCMap(mapping.getUnicodeCharMap(),
+                            "fop-ucs-H",
+                            new PDFCIDSystemInfo("Adobe", "Identity", 0));
+                    getDocument().registerObject(cmap);
+                    nonBase14.setToUnicode(cmap);
+                    */
+                }
             }
 
             return font;



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org