]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
First real step towards collapsing table borders.
authorJeremias Maerki <jeremias@apache.org>
Mon, 21 Feb 2005 21:52:14 +0000 (21:52 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 21 Feb 2005 21:52:14 +0000 (21:52 +0000)
border-collapse="collapse" rules implemented but not fully tested, yet.
Collapsing of borders works only for start and end borders, yet, and there only for non-spanned cells.
CellLM is now prepared to get the full list of grid unit it occupies (necessary for collapsed border painting).
Row.CellInfo extracted and renamed to GridUnit.
WIP...

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

src/java/org/apache/fop/fo/flow/TableBody.java
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
src/java/org/apache/fop/layoutmgr/table/Body.java
src/java/org/apache/fop/layoutmgr/table/Cell.java
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/Column.java
src/java/org/apache/fop/layoutmgr/table/GridUnit.java [new file with mode: 0644]
src/java/org/apache/fop/layoutmgr/table/Row.java
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java

index 5f30c618af768323b442b4a6f39f31cdba45f24d..28c182424c19e0df3b59529c78e697b327fb2efe 100644 (file)
@@ -152,5 +152,23 @@ public class TableBody extends FObj {
     public int getNameId() {
         return FO_TABLE_BODY;
     }
+
+    /**
+     * @param obj table row in question
+     * @return true if the given table row is the first row of this body.
+     */
+    public boolean isFirst(TableRow obj) {
+        return (childNodes.size() > 0) 
+            && (childNodes.get(0) == obj);
+    }
+
+    /**
+     * @param obj table row in question
+     * @return true if the given table row is the first row of this body.
+     */
+    public boolean isLast(TableRow obj) {
+        return (childNodes.size() > 0) 
+            && (childNodes.get(childNodes.size() - 1) == obj);
+    }
 }
 
index b9848ab0af7da89e709baed077713d1918a79d6b..fcaa0e217fe4caedceb716e8d84a43545d03c16f 100755 (executable)
@@ -75,7 +75,7 @@ public class CommonBorderPaddingBackground implements Cloneable {
     /** the "end" edge */ 
     public static final int END = 3;
 
-    private static class BorderInfo implements Cloneable {
+    public static class BorderInfo implements Cloneable {
         private int mStyle; // Enum for border style
         private ColorType mColor; // Border color
         private CondLengthProperty mWidth;
@@ -85,11 +85,52 @@ public class CommonBorderPaddingBackground implements Cloneable {
             mWidth = width;
             mColor = color;
         }
+        
+        public int getStyle() {
+            return this.mStyle;
+        }
+        
+        public ColorType getColor() {
+            return this.mColor;
+        }
+        
+        public CondLengthProperty getWidth() {
+            return this.mWidth;
+        }
+
+        public int getRetainedWidth() {
+            if ((mStyle == Constants.EN_NONE)
+                    || (mStyle == Constants.EN_HIDDEN)) {
+                return 0;
+            } else {
+                return mWidth.getLengthValue();
+            }
+        }
+        
+        /** @see java.lang.Object#toString() */
+        public String toString() {
+            StringBuffer sb = new StringBuffer("BorderInfo");
+            sb.append(" {");
+            sb.append(mStyle);
+            sb.append(", ");
+            sb.append(mColor);
+            sb.append(", ");
+            sb.append(mWidth);
+            sb.append("}");
+            return sb.toString();
+        }
     }
 
     private BorderInfo[] borderInfo = new BorderInfo[4];
     private CondLengthProperty[] padding = new CondLengthProperty[4];
 
+    /**
+     * Construct a CommonBorderPaddingBackground object.
+     */
+    public CommonBorderPaddingBackground() {
+        
+    }
+    
     /**
      * Construct a CommonBorderPaddingBackground object.
      * @param pList The PropertyList to get properties from.
@@ -159,12 +200,29 @@ public class CommonBorderPaddingBackground implements Cloneable {
         // If style = none, force width to 0, don't get Color (spec 7.7.20)
         int style = pList.get(styleProp).getEnum();
         if (style != Constants.EN_NONE) {
-            borderInfo[side] = new BorderInfo(style, 
+            setBorderInfo(new BorderInfo(style, 
                     pList.get(widthProp).getCondLength(), 
-                    pList.get(colorProp).getColorType());
+                    pList.get(colorProp).getColorType()), side);
         }
     }
     
+    /**
+     * Sets a border.
+     * @param info the border information
+     * @param side the side to apply the info to
+     */
+    public void setBorderInfo(BorderInfo info, int side) {
+        this.borderInfo[side] = info;
+    }
+    
+    /**
+     * @param side the side to retrieve
+     * @return the border info for a side
+     */
+    public BorderInfo getBorderInfo(int side) {
+        return this.borderInfo[side];
+    }
+    
     /**
      * @return the background image as a preloaded FopImage, null if there is
      *     no background image.
index 534af3e9d5177ebbd2379561f34ecdabd45b27ad..85bc59c9646999a5d1ddc5b59d7dd9ba49d9cae9 100644 (file)
@@ -313,7 +313,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
 
     public static class TableLayoutManagerMaker extends Maker {
         
-        private List getColumnLayoutManagerList(Table table) {
+        private List getColumnLayoutManagerList(Table table, TableLayoutManager tlm) {
             List columnLMs = null;
             List columns = table.getColumns();
             if (columns != null) {
@@ -329,7 +329,9 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
                         while (colnum > columnLMs.size()) {
                             columnLMs.add(null);
                         }
-                        columnLMs.set(colnum - 1, new Column(col));
+                        Column colLM = new Column(col);
+                        colLM.setParent(tlm);
+                        columnLMs.set(colnum - 1, colLM);
                         colnum++;
                     }
                 }
@@ -350,7 +352,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
         public void make(FONode node, List lms) {
             Table table = (Table) node;
             TableLayoutManager tlm = new TableLayoutManager(table);
-            List columnLMs = getColumnLayoutManagerList(table);
+            List columnLMs = getColumnLayoutManagerList(table, tlm);
             if (columnLMs != null) {
                 tlm.setColumns(columnLMs);
             }
index 9daef193da9ede608028694478e242302406da25..65ba5d966c256e7ce1a240a1c511c4f2b9561c39 100644 (file)
@@ -61,6 +61,11 @@ public class Body extends BlockStackingLayoutManager {
         fobj = node;
     }
 
+    /** @return the table-body|header|footer FO */
+    public TableBody getFObj() {
+        return this.fobj;
+    }
+    
     /**
      * Set the columns from the table.
      *
index 648528bf74edb66197586fd10469de636f8cebc3..f664f8b60adce75fabf4fe0f4266ed0d13d62761 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.flow.Table;
 import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
 import org.apache.fop.layoutmgr.LayoutManager;
@@ -59,9 +60,14 @@ public class Cell extends BlockStackingLayoutManager {
     private int cellIPD;
     private int rowHeight;
     private int usedBPD;
+    private int startBorderWidth;
+    private int endBorderWidth;
     private int borderAndPaddingBPD;
     private boolean emptyCell = true;
 
+    /** List of Lists containing GridUnit instances, one List per row. */
+    private List rows = new java.util.ArrayList(); 
+    
     /**
      * Create a new Cell layout manager.
      * @node table-cell FO for which to create the LM
@@ -102,10 +108,34 @@ public class Cell extends BlockStackingLayoutManager {
         return (Table)node;
     }
     
+
+    /**
+     * Called by Row LM to register the grid units occupied by this cell for a row.
+     * @param spannedGridUnits a List of GridUnits
+     */
+    public void addGridUnitsFromRow(List spannedGridUnits) {
+        log.debug("Getting another row, " + spannedGridUnits.size() + " grid units");
+        this.rows.add(spannedGridUnits);
+        
+    }
+
     private int getIPIndents() {
         int iIndents = 0;
-        iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
-        iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
+        startBorderWidth = 0;
+        endBorderWidth = 0;
+        for (int i = 0; i < rows.size(); i++) {
+            List gridUnits = (List)rows.get(i);
+            startBorderWidth = Math.max(startBorderWidth, 
+                    ((GridUnit)gridUnits.get(0)).
+                        effBorders.getBorderStartWidth(false));
+            endBorderWidth = Math.max(endBorderWidth, 
+                    ((GridUnit)gridUnits.get(gridUnits.size() - 1)).
+                        effBorders.getBorderEndWidth(false));
+        }
+        //iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
+        iIndents += startBorderWidth;
+        //iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
+        iIndents += endBorderWidth;
         if (!fobj.isSeparateBorderModel()) {
             iIndents /= 2;
         }
@@ -277,8 +307,15 @@ public class Cell extends BlockStackingLayoutManager {
             TraitSetter.addBackground(curBlockArea, fobj.getCommonBorderPaddingBackground());
             //TODO Set these booleans right
             boolean[] outer = new boolean[] {false, false, false, false};
-            TraitSetter.addCollapsingBorders(curBlockArea, 
-                    fobj.getCommonBorderPaddingBackground(), outer);
+            if (rows.size() == 1 && ((List)rows.get(0)).size() == 1) {
+                //Can set the borders directly if there's no span
+                CommonBorderPaddingBackground effBorders =
+                    ((GridUnit)((List)rows.get(0)).get(0)).effBorders;
+                TraitSetter.addCollapsingBorders(curBlockArea, 
+                        effBorders, outer);
+            } else {
+                log.warn("TODO Add collapsed border painting for spanned cells");
+            }
         }
 
         //Handle display-align
@@ -339,7 +376,7 @@ public class Cell extends BlockStackingLayoutManager {
             curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             curBlockArea.setPositioning(Block.ABSOLUTE);
             int indent = 0;
-            indent += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
+            indent += startBorderWidth;
             if (!fobj.isSeparateBorderModel()) {
                 indent /= 2;
             }
@@ -390,5 +427,6 @@ public class Cell extends BlockStackingLayoutManager {
             childBreaks.clear();
         }
     }
+
 }
 
diff --git a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java
new file mode 100644 (file)
index 0000000..18999f0
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+/**
+ * This class is a superclass for the two collapsing border models defined
+ * in the XSL 1.0 specification.
+ */
+public abstract class CollapsingBorderModel {
+
+    /** Indicates that the cell is/starts in the first row being painted on a particular page */
+    public static final int FIRST_ROW_IN_TABLE_PART = 1;
+    /** Indicates that the cell is/ends in the last row being painted on a particular page */
+    public static final int LAST_ROW_IN_TABLE_PART  = 2;
+    /** Indicates that the cell is/starts in the first row of a body/table-header/table-footer */
+    public static final int FIRST_ROW_IN_GROUP      = 4;
+    /** Indicates that the cell is/end in the last row of a body/table-header/table-footer */
+    public static final int LAST_ROW_IN_GROUP       = 8;
+    
+    private static CollapsingBorderModel collapse = null;
+    private static CollapsingBorderModel collapseWithPrecedence = null;
+    
+    /**
+     * @param cellLM the cell
+     * @return the border model for the cell
+     */
+    public static CollapsingBorderModel getBorderModelFor(int borderCollapse) {
+        switch (borderCollapse) {
+            case Constants.EN_COLLAPSE:
+                if (collapse == null) {
+                    collapse = new CollapsingBorderModelEyeCatching();
+                }
+                return collapse;
+            case Constants.EN_COLLAPSE_WITH_PRECEDENCE:
+                if (collapseWithPrecedence == null) {
+                    //collapseWithPrecedence = new CollapsingBorderModelWithPrecedence();
+                }
+                return collapseWithPrecedence;
+            default:
+                throw new IllegalArgumentException("Illegal border-collapse mode.");
+        }
+    }
+    
+    /**
+     * @param side the side on the current cell
+     * @return the adjacent side on the neighbouring cell
+     */
+    public static int getOtherSide(int side) {
+        switch (side) {
+            case CommonBorderPaddingBackground.BEFORE:
+                return CommonBorderPaddingBackground.AFTER;
+            case CommonBorderPaddingBackground.AFTER:
+                return CommonBorderPaddingBackground.BEFORE;
+            case CommonBorderPaddingBackground.START:
+                return CommonBorderPaddingBackground.END;
+            case CommonBorderPaddingBackground.END:
+                return CommonBorderPaddingBackground.START;
+            default:
+                throw new IllegalArgumentException("Illegal parameter: side");
+        }
+    }
+    
+    /**
+     * @param side the side to investigate
+     * @return true if the adjacent cell is before or after
+     */
+    protected boolean isVerticalRelation(int side) {
+        return (side == CommonBorderPaddingBackground.BEFORE 
+                || side == CommonBorderPaddingBackground.AFTER);
+    }
+
+    
+    /**
+     * See rule 4 in 6.7.10 for the collapsing border model.
+     * @param style the border style to get the preference value for
+     * @return the preference value of the style
+     */
+    public int getPreferenceValue(int style) {
+        switch (style) {
+            case Constants.EN_DOUBLE: return 0;
+            case Constants.EN_SOLID: return -1;
+            case Constants.EN_DASHED: return -2;
+            case Constants.EN_DOTTED: return -3;
+            case Constants.EN_RIDGE: return -4;
+            case Constants.EN_OUTSET: return -5;
+            case Constants.EN_GROOVE: return -6;
+            case Constants.EN_INSET: return -6;
+            default: throw new IllegalStateException("Illegal border style: " + style);
+        }
+    }
+    
+    /**
+     * Determines the winning BorderInfo.
+     * @param current cell info of the current element
+     * @param neighbour cell info of the neighbouring element
+     * @return the winning BorderInfo
+     */
+    public abstract BorderInfo determineWinner(
+            GridUnit current, GridUnit neighbour, int side, int flags);
+    
+}
diff --git a/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java b/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java
new file mode 100644 (file)
index 0000000..e3e6103
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+/**
+ * Implements the normal "collapse" border model defined in 6.7.10 in XSL 1.0.
+ * 
+ * TODO Column groups are not yet checked in this algorithm!
+ */
+public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel {
+
+    private static final int BEFORE = CommonBorderPaddingBackground.BEFORE;
+    private static final int AFTER = CommonBorderPaddingBackground.AFTER;
+    private static final int START = CommonBorderPaddingBackground.START;
+    private static final int END = CommonBorderPaddingBackground.END;
+    
+    public BorderInfo determineWinner(GridUnit currentGridUnit, 
+            GridUnit otherGridUnit, int side, int flags) {
+        final boolean vertical = isVerticalRelation(side);
+        final int otherSide = getOtherSide(side);
+        
+        //Get cells
+        Cell currentCell = currentGridUnit.layoutManager;
+        Cell otherCell = null;
+        if (otherGridUnit != null) {
+            otherCell = otherGridUnit.layoutManager;
+        }
+        
+        //Get rows
+        Row currentRow = currentGridUnit.row;
+        Row otherRow = null;
+        if (vertical && otherCell != null) {
+            otherRow = otherGridUnit.row;
+        }
+        
+        //get bodies
+        Body currentBody = (Body)currentRow.getParent();
+        Body otherBody = null;
+        if (otherRow != null) {
+            otherBody = (Body)otherRow.getParent();
+        }
+
+        //get columns
+        Column currentColumn = (Column)currentGridUnit.column;
+        Column otherColumn = null;
+        if (otherGridUnit != null) {
+            otherColumn = (Column)otherGridUnit.column;
+        }
+        
+        //TODO get column groups
+        
+        //Get table
+        TableLayoutManager table = (TableLayoutManager)currentBody.getParent();
+        
+        //----------------------------------------------------------------------
+        //We're creating two arrays containing the applicable BorderInfos for
+        //each cell in question.
+        //0 = cell, 1 = row, 2 = row group (body), 3 = column, 
+        //4 = col group (spanned column, see 6.7.3), 5 = table
+
+        BorderInfo[] current = new BorderInfo[6];
+        BorderInfo[] other = new BorderInfo[6];
+        //cell
+        current[0] = currentGridUnit.getOriginalBorderInfoForCell(side);
+        if (otherGridUnit != null) {
+            other[0] = otherGridUnit.getOriginalBorderInfoForCell(otherSide);
+        }
+        if (side == BEFORE 
+                || side == AFTER
+                || (currentColumn.isFirst() && side == START)
+                || (currentColumn.isLast() && side == END)) {
+            //row
+            current[1] = currentRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+        }
+        if (otherRow != null) {
+            //row
+            other[1] = otherRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+        }
+        if ((side == BEFORE && currentRow.isFirstInBody())
+                || (side == AFTER && currentRow.isLastInBody())
+                || (currentColumn.isFirst() && side == START)
+                || (currentColumn.isLast() && side == END)) {
+            //row group (=body, table-header or table-footer)
+            current[2] = currentBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+        }
+        if ((otherSide == BEFORE && otherRow.isFirstInBody())
+                || (otherSide == AFTER && otherRow.isLastInBody())) {
+            //row group (=body, table-header or table-footer)
+            other[2] = otherBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+        }
+        if ((side == BEFORE && otherGridUnit == null)
+                || (side == AFTER && otherGridUnit == null)
+                || (side == START)
+                || (side == END)) {
+            //column
+            current[3] = currentColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+        }
+        if (otherColumn != null) {
+            //column
+            other[3] = otherColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+        }
+        //TODO current[4] and other[4] for column groups
+        if (otherGridUnit == null) {
+            //table
+            current[5] = table.getTable().getCommonBorderPaddingBackground().getBorderInfo(side);
+        }
+        //other[6] is always null, since it's always the same table
+        
+        BorderInfo resolved = null;
+        
+        // *** Rule 1 ***
+        resolved = doRule1(current, other);
+        if (resolved != null) {
+            return resolved;
+        }
+        
+        // *** Rule 2 ***
+        if (!doRule2(current, other)) {
+            return null; //paint no border
+        }
+        
+        // *** Rule 3 ***
+        resolved = doRule3(current, other);
+        if (resolved != null) {
+            return resolved;
+        }
+        
+        // *** Rule 4 ***
+        resolved = doRule4(current, other);
+        if (resolved != null) {
+            return resolved;
+        }
+        
+        // *** Rule 5 ***
+        resolved = doRule5(current, other);
+        if (resolved != null) {
+            return resolved;
+        }
+        
+        return null; //no winner, no border
+    }
+
+    private BorderInfo doRule1(BorderInfo[] current, BorderInfo[] other) {
+        for (int i = 0; i < current.length - 1; i++) {
+            if ((current[i] != null) && (current[i].getStyle() == Constants.EN_HIDDEN)) {
+                return current[i];
+            }
+            if ((other[i] != null) && (other[i].getStyle() == Constants.EN_HIDDEN)) {
+                return other[i];
+            }
+        }
+        return null;
+    }
+    
+    private boolean doRule2(BorderInfo[] current, BorderInfo[] other) {
+        boolean found = false;
+        for (int i = 0; i < current.length - 1; i++) {
+            if ((current[i] != null) && (current[i].getStyle() != Constants.EN_NONE)) {
+                found = true;
+                break;
+            }
+            if ((other[i] != null) && (other[i].getStyle() != Constants.EN_NONE)) {
+                found = true;
+                break;
+            }
+        }
+        return found;
+    }
+
+    private BorderInfo doRule3(BorderInfo[] current, BorderInfo[] other) {
+        int width = 0;
+        //Find max border width
+        for (int i = 0; i < current.length - 1; i++) {
+            if ((current[i] != null) && (current[i].getRetainedWidth() > width)) {
+                width = current[i].getRetainedWidth();
+            }
+            if ((other[i] != null) && (other[i].getRetainedWidth() > width)) {
+                width = other[i].getRetainedWidth();
+            }
+        }
+        BorderInfo widest = null;
+        int count = 0;
+        //See if there's only one with the widest border
+        for (int i = 0; i < current.length - 1; i++) {
+            if ((current[i] != null) && (current[i].getRetainedWidth() == width)) {
+                count++;
+                if (widest == null) {
+                    widest = current[i];
+                }
+                break;
+            } else {
+                current[i] = null; //Discard the narrower ones
+            }
+            if ((other[i] != null) && (other[i].getRetainedWidth() == width)) {
+                count++;
+                if (widest == null) {
+                    widest = other[i];
+                }
+                break;
+            } else {
+                other[i] = null; //Discard the narrower ones
+            }
+        }
+        if (count == 1) {
+            return widest;
+        } else {
+            return null;
+        }
+    }
+
+    private BorderInfo doRule4(BorderInfo[] current, BorderInfo[] other) {
+        int pref = getPreferenceValue(Constants.EN_INSET); //Lowest preference
+        //Find highest preference value
+        for (int i = 0; i < current.length - 1; i++) {
+            if (current[i] != null) {
+                int currPref = getPreferenceValue(current[i].getStyle());
+                if (currPref > pref) {
+                    pref = currPref;
+                    break;
+                }
+            }
+            if (other[i] != null) {
+                int currPref = getPreferenceValue(other[i].getStyle());
+                if (currPref > pref) {
+                    pref = currPref;
+                    break;
+                }
+            }
+        }
+        BorderInfo preferred = null;
+        int count = 0;
+        //See if there's only one with the preferred border style
+        for (int i = 0; i < current.length - 1; i++) {
+            if (current[i] != null) {
+                int currPref = getPreferenceValue(current[i].getStyle());
+                if (currPref == pref) {
+                    count++;
+                    if (preferred == null) {
+                        preferred = current[i];
+                    }
+                    break;
+                }
+            } else {
+                current[i] = null; //Discard the ones that are not preferred
+            }
+            if (other[i] != null) {
+                int currPref = getPreferenceValue(other[i].getStyle());
+                if (currPref == pref) {
+                    count++;
+                    if (preferred == null) {
+                        preferred = other[i];
+                    }
+                    break;
+                }
+            } else {
+                other[i] = null; //Discard the ones that are not preferred
+            }
+        }
+        if (count == 1) {
+            return preferred;
+        } else {
+            return null;
+        }
+    }
+
+    private BorderInfo doRule5(BorderInfo[] current, BorderInfo[] other) {
+        for (int i = 0; i < current.length - 1; i++) {
+            if (current[i] != null) {
+                return current[i];
+            }
+            if (other[i] != null) {
+                return other[i];
+            }
+        }
+        return null;
+    }
+
+}
index be8bafa235bfb3cf7777907b630ec471b73d1c3f..a09d6f788210be4e3ed5db4b4e78a5de42754abc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 The Apache Software Foundation.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import org.apache.fop.layoutmgr.BreakPoss;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.fo.flow.TableCell;
 import org.apache.fop.fo.flow.TableColumn;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Block;
@@ -35,17 +36,36 @@ import org.apache.fop.area.Block;
  * column properties.
  */
 public class Column extends AbstractLayoutManager {
+    
     private TableColumn fobj;
     
+    private Length columnWidth;
 
     /**
      * Create a new column layout manager.
+     * @param node the table-column FO
      */
     public Column(TableColumn node) {
          super(node);
          fobj = node;
+         columnWidth = fobj.getColumnWidth();
     }
 
+    /** @return the table-column FO */
+    public TableColumn getFObj() {
+        return this.fobj;
+    }
+    
+    /** @return true if the column is the first column */
+    public boolean isFirst() {
+        return ((TableLayoutManager)getParent()).isFirst(this);
+    }
+    
+    /** @return true if the column is the last column */
+    public boolean isLast() {
+        return ((TableLayoutManager)getParent()).isLast(this);
+    }
+    
     /**
      * Get the next break possibility.
      * Columns do not create or return any areas.
@@ -80,13 +100,21 @@ public class Column extends AbstractLayoutManager {
         return null;
     }
 
+    /**
+     * Overrides the default column-with coming from the FO.
+     * @param width the new width to use
+     */
+    public void setWidth(Length width) {
+        this.columnWidth = width;
+    }
+    
     /**
      * Get the width of this column.
      *
      * @return the width of the column
      */
     public Length getWidth() {
-        return fobj.getColumnWidth();
+        return columnWidth;
     }
 
     /**
diff --git a/src/java/org/apache/fop/layoutmgr/table/GridUnit.java b/src/java/org/apache/fop/layoutmgr/table/GridUnit.java
new file mode 100644 (file)
index 0000000..e89f9d8
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.layoutmgr.table;
+
+import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+
+public class GridUnit {
+    
+    /** layout manager for the cell occupying this grid unit, may be null */
+    public Cell layoutManager;
+    /** layout manager for the column that this grid unit belongs to */
+    public Column column;
+    /** layout manager for the row that this grid unit belongs to */
+    public Row row;
+    /** index of grid unit within cell in column direction */
+    public int colSpanIndex;
+    /** index of grid unit within cell in row direction */
+    public int rowSpanIndex;
+    /** effective borders for a cell slot (used for collapsing border model) */
+    public CommonBorderPaddingBackground effBorders;
+    
+    public GridUnit(Cell layoutManager, int colSpanIndex) {
+        this.layoutManager = layoutManager;
+        this.colSpanIndex = colSpanIndex;
+        this.rowSpanIndex = 0;
+    }
+    
+    public GridUnit(Cell layoutManager) {
+        this(layoutManager, 0);
+    }
+
+    /** @return true if the grid unit is the primary of a cell */
+    public boolean isPrimaryGridUnit() {
+        return (colSpanIndex == 0) && (rowSpanIndex == 0);
+    }
+    
+    /** @return true if the grid unit is the last in column spanning direction */
+    public boolean isLastGridUnitColSpan() {
+        if (layoutManager != null) {
+            return (colSpanIndex == layoutManager.getFObj().getNumberColumnsSpanned() - 1);
+        } else {
+            return true;
+        }
+    }
+    
+    /** @return true if the grid unit is the last in column spanning direction */
+    public boolean isLastGridUnitRowSpan() {
+        if (layoutManager != null) {
+            return (rowSpanIndex == layoutManager.getFObj().getNumberRowsSpanned() - 1);
+        } else {
+            return true;
+        }
+    }
+    
+    /** @return true if the cell is part of a span in column direction */
+    public boolean isColSpan() {
+        return (colSpanIndex > 0);
+    }
+
+    public BorderInfo getOriginalBorderInfoForCell(int side) {
+        if (layoutManager != null) {
+            return layoutManager.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Assign the borders from the given cell to this cell info. Used in
+     * case of separate border model.
+     * @param current cell to take the borders from
+     */
+    public void assignBorder(Cell current) {
+        if (current != null) {
+            this.effBorders = current.getFObj().getCommonBorderPaddingBackground();
+        }
+    }
+    
+    /**
+     * Assign the borders directly.
+     * @param borders the borders to use
+     */
+    public void assignBorder(CommonBorderPaddingBackground borders) {
+        if (borders != null) {
+            this.effBorders = borders;
+        }
+    }
+    
+    /**
+     * Resolve collapsing borders for the given cell and store the resulting
+     * borders in this cell info. Use in case of the collapsing border model.
+     * @param current cell to resolve borders for
+     * @param before cell before the current cell, if any
+     * @param after cell after the current cell, if any
+     * @param start cell preceeding the current cell, if any
+     * @param end cell succeeding of the current cell, if any
+     */
+    public static void resolveBorder(Table table,
+            CommonBorderPaddingBackground target,
+            GridUnit current, GridUnit other, int side) {
+        if (current == null) {
+            return;
+        }
+        
+        CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
+                table.getBorderCollapse());
+        target.setBorderInfo(
+                borderModel.determineWinner(current, other, 
+                        side, 0), side);
+    }
+    
+}
\ No newline at end of file
index f29402c12e8c1629233ad3b8bb9b4035174e52f5..87ac870a2afdd58f64dee8e5c5626492ac4bfdf9 100644 (file)
@@ -20,8 +20,10 @@ package org.apache.fop.layoutmgr.table;
 
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.flow.TableBody;
 import org.apache.fop.fo.flow.TableCell;
 import org.apache.fop.fo.flow.TableRow;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
 import org.apache.fop.layoutmgr.LayoutManager;
@@ -52,16 +54,9 @@ import java.util.ListIterator;
  */
 public class Row extends BlockStackingLayoutManager {
     
-    /** Used by CellInfo: Indicates start of cell. */
-    public static final int CI_START_OF_CELL = 0;
-    /** Used by CellInfo: Indicates part of a spanned cell in column direction. */
-    public static final int CI_COL_SPAN      = 1;
-    /** Used by CellInfo: Indicates part of a spanned cell in row direction. */
-    public static final int CI_ROW_SPAN      = 2;
-    
     private TableRow fobj;
     
-    private List cellList = null;
+    private List gridUnits = null;
     private List columns = null;
     private int referenceIPD;
     private int rowHeight;
@@ -85,6 +80,11 @@ public class Row extends BlockStackingLayoutManager {
         fobj = node;
     }
 
+    /** @return the table-row FO */
+    public TableRow getFObj() {
+        return this.fobj;
+    }
+    
     /**
      * @return the table owning this row
      */
@@ -105,8 +105,32 @@ public class Row extends BlockStackingLayoutManager {
         columns = cols;
     }
 
-    private void setupCells() {
-        cellList = new java.util.ArrayList();
+    /** @return true if this is the layout manager for the first row in a body. */
+    public boolean isFirstInBody() {
+        return ((TableBody)getFObj().getParent()).isFirst(getFObj());
+    }
+    
+    /** @return true if this is the layout manager for the last row in a body. */
+    public boolean isLastInBody() {
+        return ((TableBody)getFObj().getParent()).isLast(getFObj());
+    }
+    
+    /**
+     * Gets the Column at a given index.
+     * @param index index of the column (index must be >= 1)
+     * @return the requested Column
+     */
+    private Column getColumn(int index) {
+        int size = columns.size();
+        if (index > size - 1) {
+            return (Column)columns.get(size - 1);
+        } else {
+            return (Column)columns.get(index - 1);
+        }
+    }
+    
+    private void prepareGridUnits() {
+        gridUnits = new java.util.ArrayList();
         List availableCells = new java.util.ArrayList();
         // add cells to list
         while (childLMiter.hasNext()) {
@@ -125,55 +149,108 @@ public class Row extends BlockStackingLayoutManager {
             if (cell.hasColumnNumber()) {
                 colnum = cell.getColumnNumber();
             }
-            while (colnum > cellList.size()) {
-                cellList.add(null);
+            while (colnum > gridUnits.size()) {
+                gridUnits.add(null);
             }
-            if (cellList.get(colnum - 1) != null) {
+            if (gridUnits.get(colnum - 1) != null) {
                 log.error("Overlapping cell at position " + colnum);
             }
             //Add cell info for primary slot
-            cellList.set(colnum - 1, new CellInfo(cellLM));
+            GridUnit info = new GridUnit(cellLM);
+            info.row = this;
+            gridUnits.set(colnum - 1, info);
+            info.column = getColumn(colnum);
             
             //Add cell infos on spanned slots if any
             for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
                 colnum++;
-                if (colnum > cellList.size()) {
-                    cellList.add(new CellInfo(CI_COL_SPAN));
+                GridUnit infoSpan = new GridUnit(cellLM, j);
+                infoSpan.row = this;
+                infoSpan.column = getColumn(colnum);
+                if (colnum > gridUnits.size()) {
+                    gridUnits.add(infoSpan);
                 } else {
-                    if (cellList.get(colnum - 1) != null) {
+                    if (gridUnits.get(colnum - 1) != null) {
                         log.error("Overlapping cell at position " + colnum);
+                        //TODO throw layout exception
                     }
-                    cellList.set(colnum - 1, new CellInfo(CI_COL_SPAN));
+                    gridUnits.set(colnum - 1, infoSpan);
                 }
             }
             colnum++;
         }
         
-        //Post-processing the list (looking for gaps)
-        int pos = 1;
-        ListIterator ppIter = cellList.listIterator();
-        while (ppIter.hasNext()) {
-            CellInfo cellInfo = (CellInfo)ppIter.next();
-            if (cellInfo == null) {
-                //Add cell info on empty cell
-                ppIter.set(new CellInfo(CI_START_OF_CELL));
+        //Post-processing the list (looking for gaps and resolve start and end borders)
+        postProcessGridUnits();
+    }
+
+    private void postProcessGridUnits() {
+        for (int pos = 1; pos <= gridUnits.size(); pos++) {
+            GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
+            
+            //Empty grid units
+            if (gu == null) {
+                //Add grid unit
+                gu = new GridUnit(null);
+                gu.row = this;
+                gu.column = getColumn(pos);
+                gridUnits.set(pos - 1, gu);
+            }
+        }
+            
+        //Border resolution now that the empty grid units are filled
+        for (int pos = 1; pos <= gridUnits.size(); pos++) {
+            GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
+         
+            //Border resolution
+            if (getTable().isSeparateBorderModel()) {
+                gu.assignBorder(gu.layoutManager);
+            } else {
+                GridUnit start = null;
+                int find = pos - 1;
+                while (find >= 1) {
+                    GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+                    if (candidate.isLastGridUnitColSpan()) {
+                        start = candidate;
+                        break;
+                    }
+                    find--;
+                }
+                GridUnit end = null;
+                find = pos + 1;
+                while (find <= gridUnits.size()) {
+                    GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+                    if (candidate.isPrimaryGridUnit()) {
+                        end = candidate;
+                        break;
+                    }
+                }
+                CommonBorderPaddingBackground borders = new CommonBorderPaddingBackground();
+                GridUnit.resolveBorder(getTable(), borders, gu, 
+                        (start != null ? start : null), 
+                        CommonBorderPaddingBackground.START);
+                GridUnit.resolveBorder(getTable(), borders, gu, 
+                        (end != null ? end : null), 
+                        CommonBorderPaddingBackground.END);
+                gu.effBorders = borders;
+                //Only start and end borders here, before and after during layout
+                //TODO resolve before and after borders during layout
             }
-            pos++;
         }
     }
-
+    
     /**
      * Get the cell info for a cell.
      *
      * @param pos the position of the cell (must be >= 1)
      * @return the cell info object
      */
-    protected CellInfo getCellInfo(int pos) {
-        if (cellList == null) {
-            setupCells();
+    protected GridUnit getCellInfo(int pos) {
+        if (gridUnits == null) {
+            prepareGridUnits();
         }
-        if (pos <= cellList.size()) {
-            return (CellInfo)cellList.get(pos - 1);
+        if (pos <= gridUnits.size()) {
+            return (GridUnit)gridUnits.get(pos - 1);
         } else {
             return null;
         }
@@ -189,11 +266,10 @@ public class Row extends BlockStackingLayoutManager {
      */
     public BreakPoss getNextBreakPoss(LayoutContext context) {
         //LayoutManager curLM; // currently active LM
-        CellInfo curCellInfo; //currently active cell info
+        GridUnit curGridUnit; //currently active grid unit
 
         BreakPoss lastPos = null;
         List breakList = new java.util.ArrayList();
-        List spannedColumns = new java.util.ArrayList();
 
         int min = 0;
         int opt = 0;
@@ -205,9 +281,9 @@ public class Row extends BlockStackingLayoutManager {
         int startColumn = 1;
         boolean over = false;
 
-        while ((curCellInfo = getCellInfo(startColumn)) != null) {
-            Cell cellLM = curCellInfo.layoutManager;
-            if (curCellInfo.isColSpan()) {
+        while ((curGridUnit = getCellInfo(startColumn)) != null) {
+            Cell cellLM = curGridUnit.layoutManager;
+            if (curGridUnit.isColSpan()) {
                 //skip spanned slots
                 startColumn++;
                 continue;
@@ -227,15 +303,17 @@ public class Row extends BlockStackingLayoutManager {
                                      stackSize));
 
             //Determine which columns this cell will occupy
-            getColumnsForCell(cellLM, startColumn, spannedColumns);
+            List spannedGridUnits = new java.util.ArrayList();
+            getGridUnitsForCell(cellLM, startColumn, spannedGridUnits);
             int childRefIPD = 0;
-            for (int i = 0; i < spannedColumns.size(); i++) {
-                Column col = (Column)spannedColumns.get(i);
+            for (int i = 0; i < spannedGridUnits.size(); i++) {
+                Column col = ((GridUnit)spannedGridUnits.get(i)).column;
                 childRefIPD += col.getWidth().getValue();
             }
             childLC.setRefIPD(childRefIPD);
 
             if (cellLM != null) {
+                cellLM.addGridUnitsFromRow(spannedGridUnits);
                 cellLM.setInRowIPDOffset(ipdOffset);
                 while (!cellLM.isFinished()) {
                     if ((bp = cellLM.getNextBreakPoss(childLC)) != null) {
@@ -309,8 +387,8 @@ public class Row extends BlockStackingLayoutManager {
         boolean fin = true;
         startColumn = 1;
         //Check if any of the cell LMs haven't finished, yet
-        while ((curCellInfo = getCellInfo(startColumn)) != null) {
-            Cell cellLM = curCellInfo.layoutManager;
+        while ((curGridUnit = getCellInfo(startColumn)) != null) {
+            Cell cellLM = curGridUnit.layoutManager;
             if (cellLM == null) {
                 //skip empty cell
                 startColumn++;
@@ -333,27 +411,13 @@ public class Row extends BlockStackingLayoutManager {
         return breakPoss;
     }
 
-    /**
-     * Gets the Column at a given index.
-     * @param index index of the column (index must be >= 1)
-     * @return the requested Column
-     */
-    private Column getColumn(int index) {
-        int size = columns.size();
-        if (index > size - 1) {
-            return (Column)columns.get(size - 1);
-        } else {
-            return (Column)columns.get(index - 1);
-        }
-    }
-    
     /**
      * Determines the columns that are spanned by the given cell.
      * @param cellLM table-cell LM
      * @param startCell starting cell index (must be >= 1)
      * @param spannedColumns List to receive the applicable columns
      */
-    private void getColumnsForCell(Cell cellLM, int startCell, List spannedColumns) {
+    private void getGridUnitsForCell(Cell cellLM, int startCell, List spannedColumns) {
         int count;
         if (cellLM != null) {
             count = cellLM.getFObj().getNumberColumnsSpanned();
@@ -362,7 +426,7 @@ public class Row extends BlockStackingLayoutManager {
         }
         spannedColumns.clear();
         for (int i = 0; i < count; i++) {
-            spannedColumns.add(getColumn(startCell + i));
+            spannedColumns.add(this.gridUnits.get(startCell + i - 1));
         }
     }
 
@@ -376,13 +440,13 @@ public class Row extends BlockStackingLayoutManager {
      */
     protected void reset(Position pos) {
         //LayoutManager curLM; // currently active LM
-        CellInfo curCellInfo;
+        GridUnit curGridUnit;
         int cellIndex = 1;
 
         if (pos == null) {
-            while ((curCellInfo = getCellInfo(cellIndex)) != null) {
-                if (curCellInfo.layoutManager != null) {
-                    curCellInfo.layoutManager.resetPosition(null);
+            while ((curGridUnit = getCellInfo(cellIndex)) != null) {
+                if (curGridUnit.layoutManager != null) {
+                    curGridUnit.layoutManager.resetPosition(null);
                 }
                 cellIndex++;
             }
@@ -390,10 +454,10 @@ public class Row extends BlockStackingLayoutManager {
             RowPosition rpos = (RowPosition)pos;
             List breaks = rpos.cellBreaks;
 
-            while ((curCellInfo = getCellInfo(cellIndex)) != null) {
-                if (curCellInfo.layoutManager != null) {
+            while ((curGridUnit = getCellInfo(cellIndex)) != null) {
+                if (curGridUnit.layoutManager != null) {
                     List childbreaks = (List)breaks.get(cellIndex);
-                    curCellInfo.layoutManager.resetPosition(
+                    curGridUnit.layoutManager.resetPosition(
                             (Position)childbreaks.get(childbreaks.size() - 1));
                 }
                 cellIndex++;
@@ -540,27 +604,5 @@ public class Row extends BlockStackingLayoutManager {
         }
     }
 
-    private class CellInfo {
-        
-        /** layout manager for this cell, may be null */
-        public Cell layoutManager;
-        /** flags for this cell, on of Row.CI_* */
-        public int flags = CI_START_OF_CELL;
-        
-        public CellInfo(Cell layoutManager) {
-            this.layoutManager = layoutManager;
-        }
-        
-        public CellInfo(int flags) {
-            this.flags = flags;
-        }
-        
-        /** @return true if the cell is part of a span in column direction */
-        public boolean isColSpan() {
-            return (flags & CI_COL_SPAN) != 0;
-        }
-
-    }
-    
 }
 
index 5a1ee47d217f1b8f78a3cc3ba7bb2bbd307058a2..37fe8cd782f1b52e8912ba8fc8d2b5f9c9dac4b9 100644 (file)
@@ -280,10 +280,28 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
         //new property evaluation context so proportional-column-width() works
         //correctly.
         if (columns.size() == 0) {
-            this.columns.add(new Column(getTable().getDefaultColumn()));
+            Column col = new Column(getTable().getDefaultColumn());
+            col.setParent(this);
+            this.columns.add(col);
         }
     }
     
+    /**
+     * @param column the column to check
+     * @return true if the column is the first column
+     */
+    public boolean isFirst(Column column) {
+        return (this.columns.size() == 0 || this.columns.get(0) == column);
+    }
+    
+    /**
+     * @param column the column to check
+     * @return true if the column is the last column
+     */
+    public boolean isLast(Column column) {
+        return (this.columns.size() == 0 || this.columns.get(columns.size() - 1) == column);
+    }
+    
     /**
      * Get the break possibility and height of the table header or footer.
      *
@@ -455,6 +473,6 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
             reset(null);
         }
     }
-    
+
 }