This implements support for HTML frames. Right now it supports frame
layout by absolute, percent (%) and relative (*) values. It misses frame
borders and margins, but these will be added real soon.

It can even layout frames in grids (when both the rows and cols
attributes are set on a frameset). This is one more feature that is not
supported by Sun:

http://kennke.org/~roman/framesgridsun.png
http://kennke.org/~roman/framesgridcp.png
http://kennke.org/~roman/frames.html

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

        * javax/swing/text/html/FrameSetView.java: New class. Implements
        HTML framesets.
        * javax/swing/text/html/FrameView.java: New class. Implements
        HTML frames.
        * javax/swing/text/html/HTMLDocument.java:
        (HTMLReader.addSpecialElement): Only add one artificial space.
        * javax/swing/text/html/HTMLEditorKit.java
        (HTMLFactory.create): Uncomment code for FrameSetView and FrameView.
        * gnu/javax/swing/text/html/parser/support/Parser.java
        (_handleEmptyTag): Also consume whitespace after frame tags.

/Roman
Index: javax/swing/text/html/FrameSetView.java
===================================================================
RCS file: javax/swing/text/html/FrameSetView.java
diff -N javax/swing/text/html/FrameSetView.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ javax/swing/text/html/FrameSetView.java	30 Nov 2006 13:41:59 -0000
@@ -0,0 +1,274 @@
+/* FrameSetView.java -- Implements HTML frameset
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.util.StringTokenizer;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BoxView;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * Implements HTML framesets. This is implemented as a vertical box that
+ * holds the rows of the frameset. Each row is again a horizontal box that
+ * holds the actual columns.
+ */
+public class FrameSetView
+  extends BoxView
+{
+
+  /**
+   * A row of a frameset.
+   */
+  private class FrameSetRow
+    extends BoxView
+  {
+    private int row;
+    FrameSetRow(Element el, int r)
+    {
+      super(el, X_AXIS);
+      row = r;
+    }
+
+    protected void loadChildren(ViewFactory f)
+    {
+      // Load the columns here.
+      Element el = getElement();
+      View[] columns = new View[numViews[X_AXIS]];
+      int offset = row * numViews[X_AXIS];
+      for (int c = 0; c < numViews[X_AXIS]; c++)
+        {
+          Element child = el.getElement(offset + c);
+          columns[c] = f.create(child);
+        }
+      replace(0, 0, columns);
+    }
+
+    protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+                                   int[] spans)
+    {
+      int numRows = numViews[X_AXIS];
+      int[] abs = absolute[X_AXIS];
+      int[] rel = relative[X_AXIS];
+      int[] perc = percent[X_AXIS];
+      layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+    }
+  }
+
+  /**
+   * Holds the absolute layout information for the views along one axis. The
+   * indices are absolute[axis][index], where axis is either X_AXIS (columns)
+   * or Y_AXIS (rows). Rows or columns that don't have absolute layout have
+   * a -1 in this array.
+   */
+  int[][] absolute;
+
+  /**
+   * Holds the relative (*) layout information for the views along one axis.
+   * The indices are relative[axis][index], where axis is either X_AXIS
+   * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+   * layout have a Float.NaN in this array.
+   */
+  int[][] relative;
+
+  /**
+   * Holds the relative (%) layout information for the views along one axis.
+   * The indices are relative[axis][index], where axis is either X_AXIS
+   * (columns) or Y_AXIS (rows). Rows or columns that don't have relative
+   * layout have a Float.NaN in this array.
+   *
+   * The percentage is divided by 100 so that we hold the actual fraction here.
+   */
+  int[][] percent;
+
+  /**
+   * The number of children in each direction.
+   */
+  int[] numViews;
+
+  FrameSetView(Element el)
+  {
+    super(el, Y_AXIS);
+    numViews = new int[2];
+    absolute = new int[2][];
+    relative = new int[2][];
+    percent = new int[2][];
+  }
+
+  /**
+   * Loads the children and places them inside the grid.
+   */
+  protected void loadChildren(ViewFactory f)
+  {
+    parseRowsCols();
+    // Set up the rows.
+    View[] rows = new View[numViews[Y_AXIS]];
+    for (int r = 0; r < numViews[Y_AXIS]; r++)
+      {
+        rows[r] = new FrameSetRow(getElement(), r);
+      }
+    replace(0, 0, rows);
+  }
+
+  /**
+   * Parses the rows and cols attributes and sets up the layout info.
+   */
+  private void parseRowsCols()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    String cols = (String) atts.getAttribute(HTML.Attribute.COLS);
+    if (cols == null) // Defaults to '100%' when not specified.
+      cols = "100%";
+    parseLayout(cols, X_AXIS);
+    String rows = (String) atts.getAttribute(HTML.Attribute.ROWS);
+    if (rows == null) // Defaults to '100%' when not specified.
+      rows = "100%";
+    parseLayout(rows, Y_AXIS);
+  }
+
+  /**
+   * Parses the cols or rows attribute and places the layout info in the
+   * appropriate arrays.
+   *
+   * @param att the attributes to parse
+   * @param axis the axis
+   */
+  private void parseLayout(String att, int axis)
+  {
+    StringTokenizer tokens = new StringTokenizer(att, ",");
+    numViews[axis] = tokens.countTokens();
+    absolute[axis] = new int[numViews[axis]];
+    relative[axis] = new int[numViews[axis]];
+    percent[axis] = new int[numViews[axis]];
+    for (int index = 0; tokens.hasMoreTokens(); index++)
+      {
+        String token = tokens.nextToken();
+        int p = token.indexOf('%');
+        int s = token.indexOf('*');
+        if (p != -1)
+          {
+            // Percent value.
+            String number = token.substring(0, p);
+            try
+              {
+                percent[axis][index] = Integer.parseInt(number);
+              }
+            catch (NumberFormatException ex)
+              {
+                // Leave value as 0 then.
+              }
+          }
+        else if (s != -1)
+          {
+            // Star relative value.
+            String number = token.substring(0, s);
+            try
+              {
+                relative[axis][index] = Integer.parseInt(number);
+              }
+            catch (NumberFormatException ex)
+              {
+                // Leave value as 0 then.
+              }
+          }
+        else
+          {
+            // Absolute value.
+            try
+              {
+                absolute[axis][index] = Integer.parseInt(token);
+              }
+            catch (NumberFormatException ex)
+              {
+                // Leave value as 0 then.
+              }
+          }
+      }
+  }
+
+  protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
+                                 int[] spans)
+  {
+    int numRows = numViews[Y_AXIS];
+    int[] abs = absolute[Y_AXIS];
+    int[] rel = relative[Y_AXIS];
+    int[] perc = percent[Y_AXIS];
+    layoutViews(targetSpan, axis, offsets, spans, numRows, abs, rel, perc);
+  }
+
+  void layoutViews(int targetSpan, int axis, int[] offsets, int[] spans,
+                   int numViews, int[] abs, int[] rel, int[] perc)
+  {
+    // We need two passes. In the first pass we layout the absolute and
+    // percent values and accumulate the needed space. In the second pass
+    // the relative values are distributed and the offsets are set.
+    int total = 0;
+    int relTotal = 0;
+    for (int i = 0; i < numViews; i++)
+      {
+        if (abs[i] > 0)
+          {
+            spans[i] = abs[i];
+            total += spans[i];
+          }
+        else if (perc[i] > 0)
+          {
+            spans[i] = (targetSpan * perc[i]) / 100;
+            total += spans[i];
+          }
+        else if (rel[i] > 0)
+          {
+            relTotal += rel[i];
+          }
+      }
+    int offs = 0;
+    for (int i = 0; i < numViews; i++)
+      {
+        if (relTotal > 0 && rel[i] > 0)
+          {
+            spans[i] = targetSpan * (rel[i] / relTotal);
+          }
+        offsets[i] = offs;
+        offs += spans[i];
+      }
+  }
+}
Index: javax/swing/text/html/FrameView.java
===================================================================
RCS file: javax/swing/text/html/FrameView.java
diff -N javax/swing/text/html/FrameView.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ javax/swing/text/html/FrameView.java	30 Nov 2006 13:41:59 -0000
@@ -0,0 +1,102 @@
+/* FrameView.java -- Renders HTML frame tags
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package javax.swing.text.html;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.JEditorPane;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+
+/**
+ * A view that is responsible for rendering HTML frame tags.
+ * This is accomplished by a specialized [EMAIL PROTECTED] ComponentView}
+ * that embeds a JEditorPane with an own document.
+ */
+class FrameView
+  extends ComponentView
+{
+
+  /**
+   * Creates a new FrameView for the specified element.
+   *
+   * @param el the element for the view
+   */
+  FrameView(Element el)
+  {
+    super(el);
+  }
+
+  /**
+   * Creates the element that will be embedded in the view.
+   * This will be a JEditorPane with the appropriate content set.
+   *
+   * @return the element that will be embedded in the view
+   */
+  protected Component createComponent()
+  {
+    Element el = getElement();
+    AttributeSet atts = el.getAttributes();
+    JEditorPane html = new JEditorPane();
+    URL base = ((HTMLDocument) el.getDocument()).getBase();
+    String srcAtt = (String) atts.getAttribute(HTML.Attribute.SRC);
+    if (srcAtt != null && ! srcAtt.equals(""))
+      {
+        try
+          {
+            URL page = new URL(base, srcAtt);
+            html.setPage(page);
+            System.err.println("loading: " + page);
+          }
+        catch (MalformedURLException ex)
+          {
+            // Leave page empty.
+          }
+        catch (IOException ex)
+          {
+            // Leave page empty.
+          }
+      }
+    return html;
+  }
+}
Index: javax/swing/text/html/HTMLDocument.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLDocument.java,v
retrieving revision 1.52
diff -u -1 -5 -r1.52 HTMLDocument.java
--- javax/swing/text/html/HTMLDocument.java	20 Nov 2006 11:18:04 -0000	1.52
+++ javax/swing/text/html/HTMLDocument.java	30 Nov 2006 13:42:00 -0000
@@ -1654,31 +1654,31 @@
       if (t != HTML.Tag.FRAME && ! inParagraph && ! inImpliedParagraph)
         {
           blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
           inParagraph = true;
           inImpliedParagraph = true;
         }
 
       a.addAttribute(StyleConstants.NameAttribute, t);
       
       // The two spaces are required because some special elements like HR
       // must be broken. At least two characters are needed to break into the
       // two parts.
       DefaultStyledDocument.ElementSpec spec =
         new DefaultStyledDocument.ElementSpec(a.copyAttributes(),
 	  DefaultStyledDocument.ElementSpec.ContentType, 
-          new char[] {' ', ' '}, 0, 2 );
+          new char[] {' '}, 0, 1 );
       parseBuffer.add(spec);
     }
     
   }
   
   /**
    * Gets the reader for the parser to use when loading the document with HTML. 
    * 
    * @param pos - the starting position
    * @return - the reader
    */
   public HTMLEditorKit.ParserCallback getReader(int pos)
   {
     return new HTMLReader(pos);
   }  
Index: javax/swing/text/html/HTMLEditorKit.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/text/html/HTMLEditorKit.java,v
retrieving revision 1.42
diff -u -1 -5 -r1.42 HTMLEditorKit.java
--- javax/swing/text/html/HTMLEditorKit.java	19 Nov 2006 19:37:36 -0000	1.42
+++ javax/swing/text/html/HTMLEditorKit.java	30 Nov 2006 13:42:01 -0000
@@ -761,38 +761,38 @@
           else if (tag == HTML.Tag.HEAD)
             view = new NullView(element);
           else if (tag.equals(HTML.Tag.TABLE))
             view = new javax.swing.text.html.TableView(element);
           else if (tag.equals(HTML.Tag.HR))
             view = new HRuleView(element);
           else if (tag.equals(HTML.Tag.BR))
             view = new BRView(element);
           else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
                    || tag.equals(HTML.Tag.TEXTAREA))
             view = new FormView(element);
 
           else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
                    || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
             view = new ListView(element);
-          // FIXME: Uncomment when the views have been implemented
-          /*
-          else if (tag.equals(HTML.Tag.OBJECT))
-            view = new ObjectView(element);
           else if (tag.equals(HTML.Tag.FRAMESET))
             view = new FrameSetView(element);
           else if (tag.equals(HTML.Tag.FRAME))
-            view = new FrameView(element); */
+            view = new FrameView(element);
+          // FIXME: Uncomment when the views have been implemented
+          /*
+          else if (tag.equals(HTML.Tag.OBJECT))
+            view = new ObjectView(element); */
         }
       if (view == null)
         {
           System.err.println("missing tag->view mapping for: " + element);
           view = new NullView(element);
         }
       return view;
     }
   }
   
   /**
    * The abstract HTML parser declaration.
    */
   public abstract static class Parser
   {
Index: gnu/javax/swing/text/html/css/FontSize.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/css/FontSize.java,v
retrieving revision 1.3
diff -u -1 -5 -r1.3 FontSize.java
--- gnu/javax/swing/text/html/css/FontSize.java	17 Nov 2006 22:12:11 -0000	1.3
+++ gnu/javax/swing/text/html/css/FontSize.java	30 Nov 2006 13:42:01 -0000
@@ -243,31 +243,31 @@
     int intVal = (int) (scale * DEFAULT_FONT_SIZE);
     sizeIndex = index;
     return intVal;
   }
 
   /**
    * Returns the string representation.
    */
   public String toString()
   {
     return value;
   }
 
   private int mapRelative(int par)
   {
-    if (value.contains("%"))
+    if (value.indexOf('%') != -1)
       size = mapPercent(par);
-    else if (value.contains("em"))
+    else if (value.indexOf("em") != -1)
       size = mapEM(par);
-    else if (value.contains("larger"))
+    else if (value.indexOf("larger") != -1)
       size = mapLarger(par);
-    else if (value.contains("smaller"))
+    else if (value.indexOf("smaller") != -1)
       size = mapSmaller(par);
     return size;
   }
 
   public boolean isRelative()
   {
     return isRelative;
   }
 }
Index: gnu/javax/swing/text/html/parser/support/Parser.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/swing/text/html/parser/support/Parser.java,v
retrieving revision 1.13
diff -u -1 -5 -r1.13 Parser.java
--- gnu/javax/swing/text/html/parser/support/Parser.java	16 Nov 2006 20:49:02 -0000	1.13
+++ gnu/javax/swing/text/html/parser/support/Parser.java	30 Nov 2006 13:42:02 -0000
@@ -1169,30 +1169,37 @@
     _handleEndTag(tag);
   }
 
   /**
    * A hooks for operations, preceeding call to handleEmptyTag().
    * Handle the tag with no content, like &lt;br&gt;. As no any
    * nested tags are expected, the tag validator is not involved.
    * @param The tag being handled.
    */
   private void _handleEmptyTag(TagElement tag)
   {
     try
       {
         validator.validateTag(tag, attributes);
         handleEmptyTag(tag);
+        HTML.Tag h = tag.getHTMLTag();
+        // When a block tag is closed, consume whitespace that follows after
+        // it.
+        // For some unknown reason a FRAME tag is not treated as block element.
+        // However in this case it should be treated as such.
+        if (h.isBlock() || h == HTML.Tag.FRAME)
+          optional(WS);
       }
     catch (ChangedCharSetException ex)
       {
         error("Changed charset exception:", ex.getMessage());
       }
   }
 
   /**
    * A hooks for operations, preceeding call to handleEndTag().
    * The method is called when the HTML closing tag
    * is found. Calls handleTitle after closing the 'title' tag.
    * @param The tag
    */
   private void _handleEndTag(TagElement tag)
   {

Reply via email to