This adds support for the HTML table cellspacing and cellpadding
attribute. Nice sideeffect, since these attributes get mapped to the CSS
padding* and border-width attributes, and these are actually
implemented, this improves general CSS support for all HTML elements.

This allows you to render the following quite nicely:
http://kennke.org/~roman/japi.png

2006-11-15  Roman Kennke  <[EMAIL PROTECTED]>

        * javax/swing/text/html/CSS.java
        (Attribute.BORDER_SPACING): New field for the CSS border-spacing
        attribute.
        * javax/swing/text/html/StyleSheet.java
        (BoxPainter.bottomPadding): New field.
        (BoxPainter.leftPadding): New field.
        (BoxPainter.rightPadding): New field.
        (BoxPainter.topPadding): New field.
        (BoxPainter.BoxPainter): Fetch the MARGIN and PADDING* attributes
        too.
        (BoxPainter.getInset): Recognize and include the padding.
        (translateHTMLToCSS): Added mapping for CELLPADDING and CELLSPACING.
         javax/swing/text/html/TableView.java
        (RowView.calculateMajorAxisRequirements): Adjust req's for
        cellSpacing.
        (RowView.layoutMajorAxis): Adjust multi-column span for cellSpacing.
        (cellSpacing): New field.
        (columnRequirements): Made package private to avoid accessor method.
        (calculateMinorAxisRequirements): Include cellSpacing.
        (calculateMajorAxisRequirements): Overridden to include cellSpacing.
        (layoutMajorAxis): Likewise.
        (layoutColumns): Respect cellSpacing.
        (setParent): Overridden to fetch the CSS attributes when view gets
        connected.
        (setPropertiesFromAttributes): New method. Fetches the cell
        spacing from the CSS attributes.

/Roman
Index: javax/swing/text/html/CSS.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/CSS.java,v
retrieving revision 1.9
diff -u -1 -5 -r1.9 CSS.java
--- javax/swing/text/html/CSS.java	11 Nov 2006 11:02:07 -0000	1.9
+++ javax/swing/text/html/CSS.java	15 Nov 2006 11:02:31 -0000
@@ -403,30 +403,32 @@
       new Attribute("border-top-style", false, null);
     static final Attribute BORDER_BOTTOM_STYLE =
       new Attribute("border-bottom-style", false, null);
     static final Attribute BORDER_LEFT_STYLE =
       new Attribute("border-left-style", false, null);
     static final Attribute BORDER_RIGHT_STYLE =
       new Attribute("border-right-style", false, null);
     static final Attribute BORDER_TOP_COLOR =
       new Attribute("border-top-color", false, null);
     static final Attribute BORDER_BOTTOM_COLOR =
       new Attribute("border-bottom-color", false, null);
     static final Attribute BORDER_LEFT_COLOR =
       new Attribute("border-left-color", false, null);
     static final Attribute BORDER_RIGHT_COLOR =
       new Attribute("border-right-color", false, null);
+    static final Attribute BORDER_SPACING =
+      new Attribute("border-spacing", false, null);
 
     /**
      * The attribute string.
      */
     String attStr;
 
     /**
      * Indicates if this attribute should be inherited from it's parent or
      * not.
      */
     boolean isInherited;
 
     /**
      * A default value for this attribute if one exists, otherwise null.
      */
@@ -504,31 +506,34 @@
       o = new FontSize(v);
     else if (att == Attribute.FONT_WEIGHT)
       o = new FontWeight(v);
     else if (att == Attribute.FONT_STYLE)
       o = new FontStyle(v);
     else if (att == Attribute.COLOR || att == Attribute.BACKGROUND_COLOR
              || att == Attribute.BORDER_COLOR
              || att == Attribute.BORDER_TOP_COLOR
              || att == Attribute.BORDER_BOTTOM_COLOR
              || att == Attribute.BORDER_LEFT_COLOR
              || att == Attribute.BORDER_RIGHT_COLOR)
       o = new CSSColor(v);
     else if (att == Attribute.MARGIN || att == Attribute.MARGIN_BOTTOM
              || att == Attribute.MARGIN_LEFT || att == Attribute.MARGIN_RIGHT
              || att == Attribute.MARGIN_TOP || att == Attribute.WIDTH
-             || att == Attribute.HEIGHT)
+             || att == Attribute.HEIGHT
+             || att == Attribute.PADDING || att == Attribute.PADDING_BOTTOM
+             || att == Attribute.PADDING_LEFT || att == Attribute.PADDING_RIGHT
+             || att == Attribute.PADDING_TOP)
       o = new Length(v);
     else if (att == Attribute.BORDER_WIDTH || att == Attribute.BORDER_TOP_WIDTH
              || att == Attribute.BORDER_LEFT_WIDTH
              || att == Attribute.BORDER_RIGHT_WIDTH
              || att == Attribute.BORDER_BOTTOM_WIDTH)
       o = new BorderWidth(v);
     else
       o = v;
     return o;
   }
 
   static void addInternal(MutableAttributeSet atts, Attribute a, String v)
   {
     if (a == Attribute.BACKGROUND)
       parseBackgroundShorthand(atts, v);
Index: javax/swing/text/html/StyleSheet.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/StyleSheet.java,v
retrieving revision 1.14
diff -u -1 -5 -r1.14 StyleSheet.java
--- javax/swing/text/html/StyleSheet.java	11 Nov 2006 11:02:07 -0000	1.14
+++ javax/swing/text/html/StyleSheet.java	15 Nov 2006 11:02:31 -0000
@@ -697,30 +697,51 @@
     o = htmlAttrSet.getAttribute(HTML.Attribute.WIDTH);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.WIDTH,
                              CSS.getValue(CSS.Attribute.WIDTH, o.toString()));
 
     // The HTML height attribute maps directly to CSS height.
     o = htmlAttrSet.getAttribute(HTML.Attribute.HEIGHT);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.HEIGHT,
                              CSS.getValue(CSS.Attribute.HEIGHT, o.toString()));
 
     o = htmlAttrSet.getAttribute(HTML.Attribute.NOWRAP);
     if (o != null)
       cssAttr = addAttribute(cssAttr, CSS.Attribute.WHITE_SPACE, "nowrap");
 
+    // Map cellspacing attr of tables to CSS border-spacing.
+    o = htmlAttrSet.getAttribute(HTML.Attribute.CELLSPACING);
+    if (o != null)
+      cssAttr = addAttribute(cssAttr, CSS.Attribute.BORDER_SPACING,
+                             new Length(o.toString()));
+
+    // For table cells and headers, fetch the cellpadding value from the
+    // parent table and set it as CSS padding attribute.
+    HTML.Tag tag = (HTML.Tag)
+                   htmlAttrSet.getAttribute(StyleConstants.NameAttribute);
+    if ((tag == HTML.Tag.TD || tag == HTML.Tag.TH)
+        && htmlAttrSet instanceof Element)
+      {
+        Element el = (Element) htmlAttrSet;
+        AttributeSet tableAttrs = el.getParentElement().getParentElement()
+                                  .getAttributes();
+        o = tableAttrs.getAttribute(HTML.Attribute.CELLPADDING);
+        if (o != null)
+          cssAttr = addAttribute(cssAttr, CSS.Attribute.PADDING,
+                                 new Length(o.toString()));
+      }
     // TODO: Add more mappings.
     return cssAttr;
   }
 
   /**
    * Adds an attribute to the given set and returns a new set. This is implemented
    * to convert StyleConstants attributes to CSS before forwarding them to the superclass.
    * The StyleConstants attribute do not have corresponding CSS entry, the attribute
    * is stored (but will likely not be used).
    * 
    * @param old - the old set
    * @param key - the non-null attribute key
    * @param value - the attribute value
    * @return the updated set 
    */
@@ -1024,99 +1045,134 @@
     /**
      * The top inset.
      */
     private float topInset;
 
     /**
      * The bottom inset.
      */
     private float bottomInset;
 
     /**
      * The border of the box.
      */
     private Border border;
 
+    private float leftPadding;
+    private float rightPadding;
+    private float topPadding;
+    private float bottomPadding;
+
     /**
      * The background color.
      */
     private Color background;
 
     /**
      * Package-private constructor.
      * 
      * @param as - AttributeSet for painter
      */
     BoxPainter(AttributeSet as, StyleSheet ss)
     {
-      Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
+      // Fetch margins.
+      Length l = (Length) as.getAttribute(CSS.Attribute.MARGIN);
+      if (l != null)
+        {
+          topInset = bottomInset = leftInset = rightInset = l.getValue();
+        }
+      l = (Length) as.getAttribute(CSS.Attribute.MARGIN_LEFT);
       if (l != null)
         leftInset = l.getValue();
       l = (Length) as.getAttribute(CSS.Attribute.MARGIN_RIGHT);
       if (l != null)
         rightInset = l.getValue();
       l = (Length) as.getAttribute(CSS.Attribute.MARGIN_TOP);
       if (l != null)
         topInset = l.getValue();
       l = (Length) as.getAttribute(CSS.Attribute.MARGIN_BOTTOM);
       if (l != null)
         bottomInset = l.getValue();
 
+      // Fetch padding.
+      l = (Length) as.getAttribute(CSS.Attribute.PADDING);
+      if (l != null)
+        {
+          leftPadding = rightPadding = topPadding = bottomPadding =
+            l.getValue();
+        }
+      l = (Length) as.getAttribute(CSS.Attribute.PADDING_LEFT);
+      if (l != null)
+        leftPadding = l.getValue();
+      l = (Length) as.getAttribute(CSS.Attribute.PADDING_RIGHT);
+      if (l != null)
+        rightPadding = l.getValue();
+      l = (Length) as.getAttribute(CSS.Attribute.PADDING_TOP);
+      if (l != null)
+        topPadding = l.getValue();
+      l = (Length) as.getAttribute(CSS.Attribute.PADDING_BOTTOM);
+      if (l != null)
+        bottomPadding = l.getValue();
+
       // Determine border.
       border = new CSSBorder(as);
 
       // Determine background.
       background = ss.getBackground(as);
 
     }
     
     
     /**
      * Gets the inset needed on a given side to account for the margin, border
      * and padding.
      * 
      * @param size - the size of the box to get the inset for. View.TOP, View.LEFT,
      * View.BOTTOM or View.RIGHT.
      * @param v - the view making the request. This is used to get the AttributeSet,
      * amd may be used to resolve percentage arguments.
      * @return the inset
      * @throws IllegalArgumentException - for an invalid direction.
      */
     public float getInset(int size, View v)
     {
       float inset;
       switch (size)
         {
         case View.TOP:
           inset = topInset;
           if (border != null)
             inset += border.getBorderInsets(null).top;
+          inset += topPadding;
           break;
         case View.BOTTOM:
           inset = bottomInset;
           if (border != null)
             inset += border.getBorderInsets(null).bottom;
+          inset += bottomPadding;
           break;
         case View.LEFT:
           inset = leftInset;
           if (border != null)
             inset += border.getBorderInsets(null).left;
+          inset += leftPadding;
           break;
         case View.RIGHT:
           inset = rightInset;
           if (border != null)
             inset += border.getBorderInsets(null).right;
+          inset += rightPadding;
           break;
         default:
           inset = 0.0F;
       }
       return inset;
     }
     
     /**
      * Paints the CSS box according to the attributes given. This should
      * paint the border, padding and background.
      * 
      * @param g - the graphics configuration
      * @param x - the x coordinate
      * @param y - the y coordinate
      * @param w - the width of the allocated area
Index: javax/swing/text/html/TableView.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/TableView.java,v
retrieving revision 1.6
diff -u -1 -5 -r1.6 TableView.java
--- javax/swing/text/html/TableView.java	14 Nov 2006 20:53:58 -0000	1.6
+++ javax/swing/text/html/TableView.java	15 Nov 2006 11:02:31 -0000
@@ -105,56 +105,59 @@
         span = totalColumnRequirements.preferred;
       else
         span = super.getPreferredSpan(axis);
       return span;
     }
 
     /**
      * Calculates the overall size requirements for the row along the
      * major axis. This will be the sum of the column requirements.
      */
     protected SizeRequirements calculateMajorAxisRequirements(int axis,
                                                             SizeRequirements r)
     {
       if (r == null)
         r = new SizeRequirements();
-      r.minimum = totalColumnRequirements.minimum;
-      r.preferred = totalColumnRequirements.preferred;
-      r.maximum = totalColumnRequirements.maximum;
+      int adjust = (columnRequirements.length + 1) * cellSpacing;
+      r.minimum = totalColumnRequirements.minimum + adjust;
+      r.preferred = totalColumnRequirements.preferred + adjust;
+      r.maximum = totalColumnRequirements.maximum + adjust;
       r.alignment = 0.0F;
       return r;
     }
 
     /**
      * Lays out the columns in this row.
      */
     protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
                                    int spans[])
     {
       int numCols = offsets.length;
       int realColumn = 0;
       for (int i = 0; i < numCols; i++)
         {
           View v = getView(i);
           if (v instanceof CellView)
             {
               CellView cv = (CellView) v;
               offsets[i] = columnOffsets[realColumn];
               spans[i] = 0;
               for (int j = 0; j < cv.colSpan; j++, realColumn++)
                 {
                   spans[i] += columnSpans[realColumn];
+                  if (j < cv.colSpan - 1)
+                    spans[i] += cellSpacing;
                 }
             }
         }
     }
   }
 
   /**
    * A view that renders HTML table cells (TD and TH tags).
    */
   class CellView
     extends BlockView
   {
 
     /**
      * The number of columns that this view spans.
@@ -199,32 +202,34 @@
               // Couldn't parse the colspan, assume 1.
               colSpan = 1;
             }
         }
     }
   }
 
 
   /**
    * The attributes of this view.
    */
   private AttributeSet attributes;
 
   /**
    * The column requirements.
+   *
+   * Package private to avoid accessor methods.
    */
-  private SizeRequirements[] columnRequirements;
+  SizeRequirements[] columnRequirements;
 
   /**
    * The overall requirements across all columns.
    *
    * Package private to avoid accessor methods.
    */
   SizeRequirements totalColumnRequirements;
 
   /**
    * The column layout, offsets.
    *
    * Package private to avoid accessor methods.
    */
   int[] columnOffsets;
 
@@ -234,30 +239,37 @@
    * Package private to avoid accessor methods.
    */
   int[] columnSpans;
 
   /**
    * The widths of the columns that have been explicitly specified.
    */
   Length[] columnWidths;
 
   /**
    * Indicates if the grid setup is ok.
    */
   private boolean gridValid;
 
   /**
+   * Additional space that is added _between_ table cells.
+   *
+   * This is package private to avoid accessor methods.
+   */
+  int cellSpacing;
+
+  /**
    * Creates a new HTML table view for the specified element.
    *
    * @param el the element for the table view
    */
   public TableView(Element el)
   {
     super(el, Y_AXIS);
     totalColumnRequirements = new SizeRequirements();
   }
 
   /**
    * Implementation of the ViewFactory interface for creating the
    * child views correctly.
    */
   public View create(Element elem)
@@ -334,44 +346,51 @@
 
     // Calculate the horizontal requirements according to the superclass.
     // This will return the maximum of the row's widths.
     r = super.calculateMinorAxisRequirements(axis, r);
 
     // Try to set the CSS width if it fits.
     AttributeSet atts = getAttributes();
     Length l = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
     if (l != null)
       {
         int width = (int) l.getValue();
         if (r.minimum < width)
           r.minimum = width;
       }
 
+    // Adjust requirements when we have cell spacing.
+    int adjust = (columnRequirements.length + 1) * cellSpacing;
+    r.minimum += adjust;
+    r.preferred += adjust;
+
     // Apply the alignment.
     Object o = atts.getAttribute(CSS.Attribute.TEXT_ALIGN);
     r.alignment = 0.0F;
     if (o != null)
       {
         String al = o.toString();
         if (al.equals("left"))
           r.alignment = 0.0F;
         else if (al.equals("center"))
           r.alignment = 0.5F;
         else if (al.equals("right"))
           r.alignment = 1.0F;
       }
 
+    // Make it not resize in the horizontal direction.
+    r.maximum = r.preferred;
     return r;
   }
 
   /**
    * Overridden to perform the table layout before calling the super
    * implementation.
    */
   protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, 
                                  int[] spans)
   {
     updateGrid();
     layoutColumns(targetSpan);
     super.layoutMinorAxis(targetSpan, axis, offsets, spans);
   }
 
@@ -549,31 +568,33 @@
     // Set the spans to the preferred sizes. Determine the space
     // that we have to adjust the sizes afterwards.
     long sumPref = 0;
     int n = columnRequirements.length;
     for (int i = 0; i < n; i++)
       {
         SizeRequirements col = columnRequirements[i];
         if (columnWidths[i] != null)
           columnSpans[i] = (int) columnWidths[i].getValue(targetSpan);
         else
           columnSpans[i] = col.preferred;
         sumPref += columnSpans[i];
       }
 
     // Try to adjust the spans so that we fill the targetSpan.
-    long diff = targetSpan - sumPref;
+    // For adjustments we have to use the targetSpan minus the cumulated
+    // cell spacings.
+    long diff = targetSpan - (n + 1) * cellSpacing - sumPref;
     float factor = 0.0F;
     int[] diffs = null;
     if (diff != 0)
       {
         long total = 0;
         diffs = new int[n];
         for (int i = 0; i < n; i++)
           {
             // Only adjust the width if we haven't set a column width here.
             if (columnWidths[i] == null)
               {
                 SizeRequirements col = columnRequirements[i];
                 int span;
                 if (diff < 0)
                   {
@@ -586,42 +607,42 @@
                     diffs[i] = span - columnSpans[i];
                   }
                 total += span;
               }
             else
               total += columnSpans[i];
           }
 
         float maxAdjust = Math.abs(total - sumPref);
         factor = diff / maxAdjust;
         factor = Math.min(factor, 1.0F);
         factor = Math.max(factor, -1.0F);
       }
 
     // Actually perform adjustments.
-    int totalOffs = 0;
+    int totalOffs = cellSpacing;
     for (int i = 0; i < n; i++)
       {
         columnOffsets[i] = totalOffs;
         if (diff != 0)
           {
             float adjust = factor * diffs[i];
             columnSpans[i] += Math.round(adjust);
           }
         // Avoid overflow here.
-        totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i],
-                                    Integer.MAX_VALUE);
+        totalOffs = (int) Math.min((long) totalOffs + (long) columnSpans[i]
+                                   + (long) cellSpacing, Integer.MAX_VALUE);
       }
   }
 
   /**
    * Updates the arrays that contain the row and column data in response
    * to a change to the table structure.
    */
   private void updateGrid()
   {
     if (! gridValid)
       {
         int maxColumns = 0;
         int numRows = getViewCount();
         for (int r = 0; r < numRows; r++)
           {
@@ -660,16 +681,68 @@
       }
   }
 
   /**
    * Overridden to restrict the table width to the preferred size.
    */
   public float getMaximumSpan(int axis)
   {
     float span;
     if (axis == X_AXIS)
       span = super.getPreferredSpan(axis);
     else
       span = super.getMaximumSpan(axis);
     return span;
   }
+
+  /**
+   * Overridden to fetch the CSS attributes when view gets connected.
+   */
+  public void setParent(View parent)
+  {
+    super.setParent(parent);
+    if (parent != null)
+      setPropertiesFromAttributes();
+  }
+
+  /**
+   * Fetches CSS and HTML layout attributes.
+   */
+  private void setPropertiesFromAttributes()
+  {
+    // Fetch and parse cell spacing.
+    Object o = getAttributes().getAttribute(CSS.Attribute.BORDER_SPACING);
+    if (o != null && o instanceof Length)
+      {
+        Length l = (Length) o;
+        cellSpacing = (int) l.getValue();
+      }
+  }
+
+  /**
+   * Overridden to adjust for cellSpacing.
+   */
+  protected SizeRequirements calculateMajorAxisRequirements(int axis,
+                                                            SizeRequirements r)
+  {
+    r = super.calculateMajorAxisRequirements(axis, r);
+    int adjust = (getViewCount() + 1) * cellSpacing;
+    r.minimum += adjust;
+    r.preferred += adjust;
+    r.maximum += adjust;
+    return r;
+  }
+
+  /**
+   * Overridden to adjust for cellSpacing.
+   */
+  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+                                 int spans[])
+  {
+    int adjust = (getViewCount() + 1) * cellSpacing;
+    super.layoutMajorAxis(targetSpan - adjust, axis, offsets, spans);
+    for (int i = 0; i < offsets.length; i++)
+      {
+        offsets[i] += (i + 1) * cellSpacing;
+      }
+  }
 }

Reply via email to