Adds many enumerated values and overloads to Style. Also adds a bunch of useful
methods to Element, Node, and Text.
Review: http://gwt-code-reviews.appspot.com/33802


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5359 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index fab0c63..a272d52 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -210,13 +210,15 @@
     return sib;
   }-*/;
 
-  public native Element getParentElement(Element elem) /*-{
-    var parent = elem.parentNode;
-    if (parent == null) {
-      return null;
-    }
-    if (parent.nodeType != 1)
+  public native int getNodeType(Node node) /*-{
+    return node.nodeType;
+  }-*/;
+
+  public native Element getParentElement(Node node) /*-{
+    var parent = node.parentNode;
+    if (!parent || parent.nodeType != 1) {
       parent = null;
+    }
     return parent;
   }-*/;
 
@@ -232,6 +234,10 @@
     return doc.getViewportElement().getScrollTop();
   }
 
+  public native String getTagName(Element elem) /*-{
+    return elem.tagName;
+  }-*/;
+
   public native String imgGetSrc(Element img) /*-{
     return img.src;
   }-*/;
@@ -240,7 +246,7 @@
     img.src = src;
   }-*/;
 
-  public abstract boolean isOrHasChild(Element parent, Element child);
+  public abstract boolean isOrHasChild(Node parent, Node child);
 
   public native void scrollIntoView(Element elem) /*-{
     var left = elem.offsetLeft, top = elem.offsetTop;
@@ -325,4 +331,8 @@
   public native String toString(Element elem) /*-{
     return elem.outerHTML;
   }-*/;
+
+  public native boolean hasAttribute(Element elem, String name) /*-{
+    return elem.hasAttribute(name);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
index d348747..ca5bd87 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -43,6 +43,11 @@
     return super.getScrollLeft(elem);
   }
 
+  public native boolean hasAttribute(Element elem, String name) /*-{
+    var node = elem.getAttributeNode(name);
+    return node && node.specified;
+  }-*/;
+
   /*
    * The src may not be set yet because of funky logic in setImgSrc(). See
    * setImgSrc().
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index c1c52c7..6a04fed 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
@@ -67,6 +67,21 @@
   }-*/;
 
   @Override
+  public native int getNodeType(Node node) /*-{
+    try {
+      return node.nodeType;
+    } catch (e) {
+      // Give up on 'Permission denied to get property HTMLDivElement.nodeType'
+      // '0' is not a valid node type, which is appropriate in this case, since
+      // the node in question is completely inaccessible.
+      //
+      // See https://bugzilla.mozilla.org/show_bug.cgi?id=208427
+      // and http://code.google.com/p/google-web-toolkit/issues/detail?id=1909
+      return 0;
+    }
+  }-*/;
+
+  @Override
   public int getScrollLeft(Element elem) {
     if (!isGecko19() && isRTL(elem)) {
       return super.getScrollLeft(elem)
@@ -76,7 +91,7 @@
   }
 
   @Override
-  public native boolean isOrHasChild(Element parent, Element child) /*-{
+  public native boolean isOrHasChild(Node parent, Node child) /*-{
     // For more information about compareDocumentPosition, see:
     // http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
     return (parent === child) || !!(parent.compareDocumentPosition(child) & 16);
diff --git a/user/src/com/google/gwt/dom/client/DOMImplSafari.java b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
index d5f7d6a..cd5b387 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplSafari.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplSafari.java
@@ -170,7 +170,7 @@
   }
 
   @Override
-  public native boolean isOrHasChild(Element parent, Element child) /*-{
+  public native boolean isOrHasChild(Node parent, Node child) /*-{
     while (child) {
       if (parent == child) {
         return true;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
index 90d2e89..2925260 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -114,7 +114,7 @@
   }-*/;
 
   @Override
-  public native boolean isOrHasChild(Element parent, Element child) /*-{
+  public native boolean isOrHasChild(Node parent, Node child) /*-{
     return parent.contains(child);
   }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/DOMImplTrident.java b/user/src/com/google/gwt/dom/client/DOMImplTrident.java
index 967d95a..d1b5e59 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplTrident.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplTrident.java
@@ -27,6 +27,27 @@
   private static EventTarget currentEventTarget;
 
   @Override
+  public Element createElement(Document doc, String tagName) {
+    if (tagName.contains(":")) {
+      // Special implementation for tag names with namespace-prefixes. The only
+      // way to get IE to reliably create namespace-prefixed elements is
+      // through innerHTML.
+      Element container = ensureContainer(doc);
+      container.setInnerHTML("<" + tagName + "/>");
+
+      // Remove the element before returning it, so that there's no chance of
+      // it getting clobbered later.
+      Element elem = container.getFirstChildElement();
+      container.removeChild(elem);
+      return elem;
+    }
+
+    // No prefix. Just use the default implementation (don't use super impl
+    // here in case it changes at some point in the future).
+    return createElementInternal(doc, tagName);
+  }
+
+  @Override
   public native NativeEvent createHtmlEvent(Document doc, String type, boolean canBubble,
       boolean cancelable) /*-{
     // NOTE: IE doesn't support changing bubbling and canceling behavior (this
@@ -181,13 +202,36 @@
     return elem.innerText;
   }-*/;
 
-  @Override
-  public native Element getParentElement(Element elem) /*-{
-    return elem.parentElement;
-  }-*/;
+  public String getTagName(Element elem) {
+    String tagName = getTagNameInternal(elem);
+    String scopeName = getScopeNameInternal(elem);
+
+    if ("html".equalsIgnoreCase(scopeName)
+        || "undefined".equalsIgnoreCase(scopeName)) {
+      return tagName;
+    }
+
+    return scopeName + ":" + tagName;
+  }
 
   @Override
-  public native boolean isOrHasChild(Element parent, Element child) /*-{
+  public native boolean isOrHasChild(Node parent, Node child) /*-{
+    // Element.contains() doesn't work with non-Element nodes on IE, so we have
+    // to deal explicitly with non-Element nodes here.
+
+    // Only Element (1) and Document (9) can contain other nodes.
+    if ((parent.nodeType != 1) && (parent.nodeType != 9)) {
+      return parent == child;
+    }
+
+    // If the child is not an Element, check its parent instead.
+    if (child.nodeType != 1) {
+      child = child.parentNode;
+      if (!child) {
+        return false;
+      }
+    }
+
     // An extra equality check is required due to the fact that
     // elem.contains(elem) is false if elem is not attached to the DOM.
     return (parent === child) || parent.contains(child);
@@ -213,6 +257,18 @@
     return elem.currentStyle.direction == 'rtl';
   }-*/;
 
+  private native Element createElementInternal(Document doc, String tagName) /*-{
+    return doc.createElement(tagName);
+  }-*/;
+
+  // IE needs a container div *for each document* for use by createElement().
+  private native Element ensureContainer(Document doc) /*-{
+    if (!doc.__gwt_container) {
+      doc.__gwt_container = doc.createElement('div');
+    }
+    return doc.__gwt_container;
+  }-*/;
+
   private native int getBoundingClientRectLeft(Element elem) /*-{
     // getBoundingClientRect() throws a JS exception if the elem is not attached
     // to the document, so we wrap it in a try/catch block
@@ -246,4 +302,12 @@
   private native int getClientTop(Element elem) /*-{
     return elem.clientTop;
   }-*/;
+
+  private native String getScopeNameInternal(Element elem) /*-{
+    return elem.scopeName;
+  }-*/;
+
+  private native String getTagNameInternal(Element elem) /*-{
+    return elem.tagName;
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index ea2a7e4..e41f0ef 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -62,6 +62,45 @@
   }
 
   /**
+   * Adds a name to this element's class property. If the name is already
+   * present, this method has no effect.
+   * 
+   * @param the class name to be added
+   * @see #setClassName(String)
+   */
+  public final void addClassName(String className) {
+    assert (className != null) : "Unexpectedly null class name";
+
+    className = className.trim();
+    assert (className.length() != 0) : "Unexpectedly empty class name";
+
+    // Get the current style string.
+    String oldClassName = getClassName();
+    int idx = oldClassName.indexOf(className);
+
+    // Calculate matching index.
+    while (idx != -1) {
+      if (idx == 0 || oldClassName.charAt(idx - 1) == ' ') {
+        int last = idx + className.length();
+        int lastPos = oldClassName.length();
+        if ((last == lastPos)
+            || ((last < lastPos) && (oldClassName.charAt(last) == ' '))) {
+          break;
+        }
+      }
+      idx = oldClassName.indexOf(className, idx + 1);
+    }
+
+    // Only add the style if it's not already present.
+    if (idx == -1) {
+      if (oldClassName.length() > 0) {
+        oldClassName += " ";
+      }
+      setClassName(oldClassName + className);
+    }
+  }
+
+  /**
    * Dispatched the given event with this element as its target. The event will
    * go through all phases of the browser's normal event dispatch mechanism.
    * 
@@ -79,6 +118,14 @@
   }
 
   /**
+   * Gets an element's absolute bottom coordinate in the document's coordinate
+   * system.
+   */
+  public final int getAbsoluteBottom() {
+    return getAbsoluteTop() + getOffsetHeight();
+  }
+
+  /**
    * Gets an element's absolute left coordinate in the document's coordinate
    * system.
    */
@@ -87,6 +134,14 @@
   }
 
   /**
+   * Gets an element's absolute right coordinate in the document's coordinate
+   * system.
+   */
+  public final int getAbsoluteRight() {
+    return getAbsoluteLeft() + getOffsetWidth();
+  }
+
+  /**
    * Gets an element's absolute top coordinate in the document's coordinate
    * system.
    */
@@ -248,13 +303,6 @@
    }-*/;
 
   /**
-   * The parent element of this element.
-   */
-  public final Element getParentElement() {
-    return DOMImpl.impl.getParentElement(this);
-  }
-
-  /**
    * Gets a boolean property from this element.
    * 
    * @param name the name of the property to be retrieved
@@ -285,6 +333,26 @@
    }-*/;
 
   /**
+   * Gets a JSO property from this element.
+   *
+   * @param name the name of the property to be retrieved
+   * @return the property value
+   */
+  public final native JavaScriptObject getPropertyJSO(String name) /*-{
+    return this[name] || null;
+  }-*/;
+
+  /**
+   * Gets an object property from this element.
+   *
+   * @param name the name of the property to be retrieved
+   * @return the property value
+   */
+  public final native Object getPropertyObject(String name) /*-{
+    return this[name] || null;
+  }-*/;
+
+  /**
    * Gets a property from this element.
    * 
    * @param name the name of the property to be retrieved
@@ -347,11 +415,14 @@
    }-*/;
 
   /**
-   * The name of the element.
+   * Gets the element's full tag name, including the namespace-prefix if
+   * present.
+   * 
+   * @return the element's tag name
    */
-  public final native String getTagName() /*-{
-     return this.tagName;
-   }-*/;
+  public final String getTagName() {
+    return DOMImpl.impl.getTagName(this);
+  }
 
   /**
    * The element's advisory title.
@@ -361,13 +432,29 @@
    }-*/;
 
   /**
-   * Determine whether an element is equal to, or the child of, this element.
+   * Determines whether an element has an attribute with a given name.
+   *
+   * <p>
+   * Note that IE, prior to version 8, will return false-positives for names
+   * that collide with element properties (e.g., style, width, and so forth).
+   * </p>
    * 
-   * @param child the potential child element
-   * @return <code>true</code> if the relationship holds
+   * @param name the name of the attribute
+   * @return <code>true</code> if this element has the specified attribute
    */
-  public final boolean isOrHasChild(Element child) {
-    return DOMImpl.impl.isOrHasChild(this, child);
+  public final boolean hasAttribute(String name) {
+    return DOMImpl.impl.hasAttribute(this, name);
+  }
+
+  /**
+   * Determines whether this element has the given tag name.
+   * 
+   * @param tagName the tag name, including namespace-prefix (if present)
+   * @return <code>true</code> if the element has the given tag name
+   */
+  public final boolean hasTagName(String tagName) {
+    assert tagName != null : "tagName must not be null";
+    return tagName.equals(getTagName());
   }
 
   /**
@@ -378,6 +465,67 @@
    }-*/;
 
   /**
+   * Removes a name from this element's class property. If the name is not
+   * present, this method has no effect.
+   * 
+   * @param the class name to be added
+   * @see #setClassName(String)
+   */
+  public final void removeClassName(String className) {
+    assert (className != null) : "Unexpectedly null class name";
+
+    className = className.trim();
+    assert (className.length() != 0) : "Unexpectedly empty class name";
+
+    // Get the current style string.
+    String oldStyle = getClassName();
+    int idx = oldStyle.indexOf(className);
+
+    // Calculate matching index.
+    while (idx != -1) {
+      if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') {
+        int last = idx + className.length();
+        int lastPos = oldStyle.length();
+        if ((last == lastPos)
+            || ((last < lastPos) && (oldStyle.charAt(last) == ' '))) {
+          break;
+        }
+      }
+      idx = oldStyle.indexOf(className, idx + 1);
+    }
+
+    // Don't try to remove the style if it's not there.
+    if (idx != -1) {
+      // Get the leading and trailing parts, without the removed name.
+      String begin = oldStyle.substring(0, idx).trim();
+      String end = oldStyle.substring(idx + className.length()).trim();
+
+      // Some contortions to make sure we don't leave extra spaces.
+      String newClassName;
+      if (begin.length() == 0) {
+        newClassName = end;
+      } else if (end.length() == 0) {
+        newClassName = begin;
+      } else {
+        newClassName = begin + " " + end;
+      }
+
+      setClassName(newClassName);
+    }
+  }
+
+  /**
+   * Replace one class name with another.
+   *
+   * @param oldClassName the class name to be replaced
+   * @param newClassName the class name to replace it
+   */
+  public final void replaceClassName(String oldClassName, String newClassName) {
+    removeClassName(oldClassName);
+    addClassName(newClassName);
+  }
+
+  /**
    * Scrolls this element into view.
    * 
    * <p>
@@ -485,6 +633,26 @@
    }-*/;
 
   /**
+   * Sets a JSO property on this element.
+   *
+   * @param name the name of the property to be set
+   * @param value the new property value
+   */
+  public final native void setPropertyJSO(String name, JavaScriptObject value) /*-{
+    this[name] = value;
+  }-*/;
+
+  /**
+   * Sets an object property on this element.
+   *
+   * @param name the name of the property to be set
+   * @param value the new property value
+   */
+  public final native void setPropertyObject(String name, Object value) /*-{
+    this[name] = value;
+  }-*/;
+
+  /**
    * Sets a property on this element.
    * 
    * @param name the name of the property to be set
diff --git a/user/src/com/google/gwt/dom/client/Node.java b/user/src/com/google/gwt/dom/client/Node.java
index fa3e35c..aad5a1e 100644
--- a/user/src/com/google/gwt/dom/client/Node.java
+++ b/user/src/com/google/gwt/dom/client/Node.java
@@ -93,6 +93,27 @@
   }-*/;
 
   /**
+   * Gets the child node at the given index.
+   * 
+   * @param index the index of the node to be retrieved
+   * @return the child node at the given index
+   */
+  public final Node getChild(int index) {
+    assert (index >= 0) && (index < getChildCount()) : "Child index out of bounds";
+
+    return getChildNodes().getItem(index);
+  }
+
+  /**
+   * Gets the number of child nodes contained within this node.
+   * 
+   * @return the number of child nodes
+   */
+  public final int getChildCount() {
+    return getChildNodes().getLength();
+  }
+
+  /**
    * A NodeList that contains all children of this node. If there are no
    * children, this is a NodeList containing no nodes.
    */
@@ -153,6 +174,15 @@
   }-*/;
 
   /**
+   * Gets the parent element of this node.
+   * 
+   * @return this node's parent element, or <code>null</code> if none exists
+   */
+  public final Element getParentElement() {
+    return DOMImpl.impl.getParentElement(this);
+  }
+
+  /**
    * The parent of this node. All nodes except Document may have a parent.
    * However, if a node has just been created and not yet added to the tree, or
    * if it has been removed from the tree, this is null.
@@ -177,6 +207,35 @@
   }-*/;
 
   /**
+   * Determines whether this node has a parent element.
+   * 
+   * @return true if the node has a parent element
+   */
+  public final boolean hasParentElement() {
+    return getParentElement() != null;
+  }
+
+  /**
+   * Inserts the node newChild after the existing child node refChild. If
+   * refChild is <code>null</code>, insert newChild at the end of the list of children.
+   * 
+   * @param newChild The node to insert
+   * @param refChild The reference node (that is, the node after which the new
+   *          node must be inserted), or <code>null</code>
+   * @return The node being inserted
+   */
+  public final Node insertAfter(Node newChild, Node refChild) {
+    assert (newChild != null) : "Cannot add a null child node";
+
+    Node next = (refChild == null) ? null : refChild.getNextSibling();
+    if (next == null) {
+      return appendChild(newChild);
+    } else {
+      return insertBefore(newChild, next);
+    }
+  }
+
+  /**
    * Inserts the node newChild before the existing child node refChild. If
    * refChild is <code>null</code>, insert newChild at the end of the list of children.
    * 
@@ -190,6 +249,30 @@
   }-*/;
 
   /**
+   * Inserts the given child as the first child of this node.
+   * 
+   * @param child the child to be inserted
+   * @return The node being inserted
+   */
+  public final Node insertFirst(Node child) {
+    assert (child != null) : "Cannot add a null child node";
+
+    return insertBefore(child, getFirstChild());
+  }
+
+  /**
+   * Determine whether a node is equal to, or the child of, this node.
+   * 
+   * @param child the potential child element
+   * @return <code>true</code> if the relationship holds
+   */
+  public final boolean isOrHasChild(Node child) {
+    assert (child != null) : "Child cannot be null";
+
+    return DOMImpl.impl.isOrHasChild(this, child);
+  }
+
+  /**
    * Removes the child node indicated by oldChild from the list of children, and
    * returns it.
    * 
@@ -201,6 +284,16 @@
   }-*/;
 
   /**
+   * Removes this node from its parent node if it is attached to one.
+   */
+  public final void removeFromParent() {
+    Element parent = getParentElement();
+    if (parent != null) {
+      parent.removeChild(this);
+    }
+  }
+
+  /**
    * Replaces the child node oldChild with newChild in the list of children, and
    * returns the oldChild node.
    * 
diff --git a/user/src/com/google/gwt/dom/client/Style.java b/user/src/com/google/gwt/dom/client/Style.java
index 56720cd..84fa2f1 100644
--- a/user/src/com/google/gwt/dom/client/Style.java
+++ b/user/src/com/google/gwt/dom/client/Style.java
@@ -20,14 +20,1033 @@
 /**
  * Provides programmatic access to properties of the style object.
  * 
+ * <p>
+ * Note that if a property or value is not explicitly enumerated in this
+ * class, you can still access it via {@link #getProperty(String)},
+ * and {@link #setProperty(String, String)}.
+ * </p>
+ * 
  * @see Element#getStyle()
  */
 public class Style extends JavaScriptObject {
 
+  /**
+   * Interface to be implemented by enumerated CSS values.
+   */
+  public interface HasCssName {
+
+    /**
+     * Gets the CSS name associated with this value.
+     */
+    String getCssName();
+  }
+
+  /**
+   * CSS length units.
+   */
+  public enum Unit {
+    PX {
+      @Override
+      public String getType() {
+        return UNIT_PX;
+      }
+    }, PCT {
+      @Override
+      public String getType() {
+        return UNIT_PCT;
+      }
+    }, EM {
+      @Override
+      public String getType() {
+        return UNIT_EM;
+      }
+    }, EX {
+      @Override
+      public String getType() {
+        return UNIT_EX;
+      }
+    }, PT {
+      @Override
+      public String getType() {
+        return UNIT_PT;
+      }
+    }, PC {
+      @Override
+      public String getType() {
+        return UNIT_PC;
+      }
+    }, IN {
+      @Override
+      public String getType() {
+        return UNIT_IN;
+      }
+    }, CM {
+      @Override
+      public String getType() {
+        return UNIT_CM;
+      }
+    }, MM {
+      @Override
+      public String getType() {
+        return UNIT_MM;
+      }
+    };
+
+    public abstract String getType();
+  }
+  /**
+   * Enum for the border-style property.
+   */
+  public enum BorderStyle implements HasCssName {
+    NONE {
+      public String getCssName() {
+        return BORDER_STYLE_NONE;
+      }
+    },
+    DOTTED {
+      public String getCssName() {
+        return BORDER_STYLE_DOTTED;
+      }
+    },
+    DASHED {
+      public String getCssName() {
+        return BORDER_STYLE_DASHED;
+      }
+    },
+    SOLID {
+      public String getCssName() {
+        return BORDER_STYLE_SOLID;
+      }
+    };
+  }
+
+  /**
+   * Enum for the cursor property.
+   */
+  public enum Cursor implements HasCssName {
+    DEFAULT {
+      public String getCssName() {
+        return CURSOR_DEFAULT;
+      }
+    },
+    AUTO {
+      public String getCssName() {
+        return CURSOR_AUTO;
+      }
+    },
+    CROSSHAIR {
+      public String getCssName() {
+        return CURSOR_CROSSHAIR;
+      }
+    },
+    POINTER {
+      public String getCssName() {
+        return CURSOR_POINTER;
+      }
+    },
+    MOVE {
+      public String getCssName() {
+        return CURSOR_MOVE;
+      }
+    },
+    E_RESIZE {
+      public String getCssName() {
+        return CURSOR_E_RESIZE;
+      }
+    },
+    NE_RESIZE {
+      public String getCssName() {
+        return CURSOR_NE_RESIZE;
+      }
+    },
+    NW_RESIZE {
+      public String getCssName() {
+        return CURSOR_NW_RESIZE;
+      }
+    },
+    N_RESIZE {
+      public String getCssName() {
+        return CURSOR_N_RESIZE;
+      }
+    },
+    SE_RESIZE {
+      public String getCssName() {
+        return CURSOR_SE_RESIZE;
+      }
+    },
+    SW_RESIZE {
+      public String getCssName() {
+        return CURSOR_SW_RESIZE;
+      }
+    },
+    S_RESIZE {
+      public String getCssName() {
+        return CURSOR_S_RESIZE;
+      }
+    },
+    W_RESIZE {
+      public String getCssName() {
+        return CURSOR_W_RESIZE;
+      }
+    },
+    TEXT {
+      public String getCssName() {
+        return CURSOR_TEXT;
+      }
+    },
+    WAIT {
+      public String getCssName() {
+        return CURSOR_WAIT;
+      }
+    },
+    HELP {
+      public String getCssName() {
+        return CURSOR_HELP;
+      }
+    },
+    COL_RESIZE {
+      public String getCssName() {
+        return CURSOR_COL_RESIZE;
+      }
+    },
+    ROW_RESIZE {
+      public String getCssName() {
+        return CURSOR_ROW_RESIZE;
+      }
+    };
+  }
+
+  /**
+   * Enum for the display property.
+   */
+  public enum Display implements HasCssName {
+    NONE {
+      public String getCssName() {
+        return DISPLAY_NONE;
+      }
+    },
+    BLOCK {
+      public String getCssName() {
+        return DISPLAY_BLOCK;
+      }
+    },
+    INLINE {
+      public String getCssName() {
+        return DISPLAY_INLINE;
+      }
+    },
+    INLINE_BLOCK {
+      public String getCssName() {
+        return DISPLAY_INLINE_BLOCK;
+      }
+    };
+  }
+
+  /**
+   * Enum for the font-style property.
+   */
+  public enum FontStyle implements HasCssName {
+    NORMAL {
+      public String getCssName() {
+        return FONT_STYLE_NORMAL;
+      }
+    },
+    ITALIC {
+      public String getCssName() {
+        return FONT_STYLE_ITALIC;
+      }
+    },
+    OBLIQUE {
+      public String getCssName() {
+        return FONT_STYLE_OBLIQUE;
+      }
+    };
+  }
+
+  /**
+   * Enum for the font-weight property.
+   */
+  public enum FontWeight implements HasCssName {
+    NORMAL {
+      public String getCssName() {
+        return FONT_WEIGHT_NORMAL;
+      }
+    },
+    BOLD {
+      public String getCssName() {
+        return FONT_WEIGHT_BOLD;
+      }
+    },
+    BOLDER {
+      public String getCssName() {
+        return FONT_WEIGHT_BOLDER;
+      }
+    },
+    LIGHTER {
+      public String getCssName() {
+        return FONT_WEIGHT_LIGHTER;
+      }
+    };
+  }
+
+  /**
+   * Enum for the list-style-type property.
+   */
+  public enum ListStyleType implements HasCssName {
+    NONE {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_NONE;
+      }
+    },
+    DISC {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_DISC;
+      }
+    },
+    CIRCLE {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_CIRCLE;
+      }
+    },
+    SQUARE {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_SQUARE;
+      }
+    },
+    DECIMAL {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_DECIMAL;
+      }
+    },
+    LOWER_ALPHA {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_LOWER_ALPHA;
+      }
+    },
+    UPPER_ALPHA {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_UPPER_ALPHA;
+      }
+    },
+    LOWER_ROMAN {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_LOWER_ROMAN;
+      }
+    },
+    UPPER_ROMAN {
+      public String getCssName() {
+        return LIST_STYLE_TYPE_UPPER_ROMAN;
+      }
+    };
+  }
+
+  /**
+   * Enum for the overflow property.
+   */
+  public enum Overflow implements HasCssName {
+    VISIBLE {
+      public String getCssName() {
+        return OVERFLOW_VISIBLE;
+      }
+    },
+    HIDDEN {
+      public String getCssName() {
+        return OVERFLOW_HIDDEN;
+      }
+    },
+    SCROLL {
+      public String getCssName() {
+        return OVERFLOW_SCROLL;
+      }
+    },
+    AUTO {
+      public String getCssName() {
+        return OVERFLOW_AUTO;
+      }
+    };
+  }
+
+  /**
+   * Enum for the display property.
+   */
+  public enum Position implements HasCssName {
+    STATIC {
+      public String getCssName() {
+        return POSITION_STATIC;
+      }
+    },
+    RELATIVE {
+      public String getCssName() {
+        return POSITION_RELATIVE;
+      }
+    },
+    ABSOLUTE {
+      public String getCssName() {
+        return POSITION_ABSOLUTE;
+      }
+    },
+    FIXED {
+      public String getCssName() {
+        return POSITION_FIXED;
+      }
+    };
+  }
+
+  /**
+   * Enum for the text-decoration property.
+   */
+  public enum TextDecoration implements HasCssName {
+    NONE {
+      public String getCssName() {
+        return TEXT_DECORATION_NONE;
+      }
+    },
+    UNDERLINE {
+      public String getCssName() {
+        return TEXT_DECORATION_UNDERLINE;
+      }
+    },
+    OVERLINE {
+      public String getCssName() {
+        return TEXT_DECORATION_OVERLINE;
+      }
+    },
+    LINE_THROUGH {
+      public String getCssName() {
+        return TEXT_DECORATION_LINE_THROUGH;
+      }
+    };
+  }
+
+  /**
+   * Enum for the vertical-align property.
+   */
+  public enum VerticalAlign implements HasCssName {
+    BASELINE {
+      public String getCssName() {
+        return VERTICAL_ALIGN_BASELINE;
+      }
+    },
+    SUB {
+      public String getCssName() {
+        return VERTICAL_ALIGN_SUB;
+      }
+    },
+    SUPER {
+      public String getCssName() {
+        return VERTICAL_ALIGN_SUPER;
+      }
+    },
+    TOP {
+      public String getCssName() {
+        return VERTICAL_ALIGN_TOP;
+      }
+    },
+    TEXT_TOP {
+      public String getCssName() {
+        return VERTICAL_ALIGN_TEXT_TOP;
+      }
+    },
+    MIDDLE {
+      public String getCssName() {
+        return VERTICAL_ALIGN_MIDDLE;
+      }
+    },
+    BOTTOM {
+      public String getCssName() {
+        return VERTICAL_ALIGN_BOTTOM;
+      }
+    },
+    TEXT_BOTTOM {
+      public String getCssName() {
+        return VERTICAL_ALIGN_TEXT_BOTTOM;
+      }
+    },
+  }
+
+  /**
+   * Enum for the visibility property.
+   */
+  public enum Visibility implements HasCssName {
+    VISIBLE {
+      public String getCssName() {
+        return VISIBILITY_VISIBLE;
+      }
+    },
+    HIDDEN {
+      public String getCssName() {
+        return VISIBILITY_HIDDEN;
+      }
+    };
+  }
+
+  private static final String BORDER_STYLE_SOLID = "solid";
+  private static final String BORDER_STYLE_DASHED = "dashed";
+  private static final String BORDER_STYLE_DOTTED = "dotted";
+  private static final String BORDER_STYLE_HIDDEN = "hidden";
+  private static final String BORDER_STYLE_NONE = "none";
+
+  private static final String CURSOR_ROW_RESIZE = "row-resize";
+  private static final String CURSOR_COL_RESIZE = "col-resize";
+  private static final String CURSOR_HELP = "help";
+  private static final String CURSOR_WAIT = "wait";
+  private static final String CURSOR_TEXT = "text";
+  private static final String CURSOR_W_RESIZE = "w-resize";
+  private static final String CURSOR_S_RESIZE = "s-resize";
+  private static final String CURSOR_SW_RESIZE = "sw-resize";
+  private static final String CURSOR_SE_RESIZE = "se-resize";
+  private static final String CURSOR_N_RESIZE = "n-resize";
+  private static final String CURSOR_NW_RESIZE = "nw-resize";
+  private static final String CURSOR_NE_RESIZE = "ne-resize";
+  private static final String CURSOR_E_RESIZE = "e-resize";
+  private static final String CURSOR_MOVE = "move";
+  private static final String CURSOR_POINTER = "pointer";
+  private static final String CURSOR_CROSSHAIR = "crosshair";
+  private static final String CURSOR_AUTO = "auto";
+  private static final String CURSOR_DEFAULT = "default";
+
+  private static final String DISPLAY_INLINE_BLOCK = "inline-block";
+  private static final String DISPLAY_INLINE = "inline";
+  private static final String DISPLAY_BLOCK = "block";
+  private static final String DISPLAY_NONE = "none";
+
+  private static final String FONT_STYLE_OBLIQUE = "oblique";
+  private static final String FONT_STYLE_ITALIC = "italic";
+  private static final String FONT_STYLE_NORMAL = "normal";
+
+  private static final String FONT_WEIGHT_LIGHTER = "lighter";
+  private static final String FONT_WEIGHT_BOLDER = "bolder";
+  private static final String FONT_WEIGHT_BOLD = "bold";
+  private static final String FONT_WEIGHT_NORMAL = "normal";
+
+  private static final String LIST_STYLE_TYPE_UPPER_ROMAN = "upper-roman";
+  private static final String LIST_STYLE_TYPE_LOWER_ROMAN = "lower-roman";
+  private static final String LIST_STYLE_TYPE_UPPER_ALPHA = "upper-alpha";
+  private static final String LIST_STYLE_TYPE_LOWER_ALPHA = "lower-alpha";
+  private static final String LIST_STYLE_TYPE_DECIMAL = "decimal";
+  private static final String LIST_STYLE_TYPE_SQUARE = "square";
+  private static final String LIST_STYLE_TYPE_CIRCLE = "circle";
+  private static final String LIST_STYLE_TYPE_DISC = "disc";
+  private static final String LIST_STYLE_TYPE_NONE = "none";
+
+  private static final String OVERFLOW_AUTO = "auto";
+  private static final String OVERFLOW_SCROLL = "scroll";
+  private static final String OVERFLOW_HIDDEN = "hidden";
+  private static final String OVERFLOW_VISIBLE = "visible";
+
+  private static final String POSITION_FIXED = "fixed";
+  private static final String POSITION_ABSOLUTE = "absolute";
+  private static final String POSITION_RELATIVE = "relative";
+  private static final String POSITION_STATIC = "static";
+
+  private static final String STYLE_Z_INDEX = "zIndex";
+  private static final String STYLE_WIDTH = "width";
+  private static final String STYLE_VISIBILITY = "visibility";
+  private static final String STYLE_TOP = "top";
+  private static final String STYLE_LIST_DECORATION = "listDecoration";
+  private static final String STYLE_RIGHT = "right";
+  private static final String STYLE_POSITION = "position";
+  private static final String STYLE_PADDING_TOP = "paddingTop";
+  private static final String STYLE_PADDING_RIGHT = "paddingRight";
+  private static final String STYLE_PADDING_LEFT = "paddingLeft";
+  private static final String STYLE_PADDING_BOTTOM = "paddingBottom";
+  private static final String STYLE_PADDING = "padding";
+  private static final String STYLE_OVERFLOW = "overflow";
+  private static final String STYLE_OPACITY = "opacity";
+  private static final String STYLE_MARGIN_TOP = "marginTop";
+  private static final String STYLE_MARGIN_RIGHT = "marginRight";
+  private static final String STYLE_MARGIN_LEFT = "marginLeft";
+  private static final String STYLE_MARGIN_BOTTOM = "marginBottom";
+  private static final String STYLE_MARGIN = "margin";
+  private static final String STYLE_LIST_STYLE_TYPE = "listStyleType";
+  private static final String STYLE_LEFT = "left";
+  private static final String STYLE_HEIGHT = "height";
+  private static final String STYLE_FONT_WEIGHT = "fontWeight";
+  private static final String STYLE_FONT_STYLE = "fontStyle";
+  private static final String STYLE_FONT_SIZE = "fontSize";
+  private static final String STYLE_DISPLAY = "display";
+  private static final String STYLE_CURSOR = "cursor";
+  private static final String STYLE_COLOR = "color";
+  private static final String STYLE_BOTTOM = "bottom";
+  private static final String STYLE_BORDER_WIDTH = "borderWidth";
+  private static final String STYLE_BORDER_STYLE = "borderStyle";
+  private static final String STYLE_BORDER_COLOR = "borderColor";
+  private static final String STYLE_BACKGROUND_IMAGE = "backgroundImage";
+  private static final String STYLE_BACKGROUND_COLOR = "backgroundColor";
+  private static final String STYLE_VERTICAL_ALIGN = "verticalAlign";
+
+  private static final String TEXT_DECORATION_LINE_THROUGH = "line-through";
+  private static final String TEXT_DECORATION_OVERLINE = "overline";
+  private static final String TEXT_DECORATION_UNDERLINE = "underline";
+  private static final String TEXT_DECORATION_NONE = "none";
+
+  private static final String UNIT_MM = "mm";
+  private static final String UNIT_CM = "cm";
+  private static final String UNIT_IN = "in";
+  private static final String UNIT_PC = "pc";
+  private static final String UNIT_PT = "pt";
+  private static final String UNIT_EX = "ex";
+  private static final String UNIT_EM = "em";
+  private static final String UNIT_PCT = "%";
+  private static final String UNIT_PX = "px";
+
+  private static final String VERTICAL_ALIGN_BASELINE = "baseline";
+  private static final String VERTICAL_ALIGN_SUB = "sub";
+  private static final String VERTICAL_ALIGN_SUPER = "super";
+  private static final String VERTICAL_ALIGN_TOP = "top";
+  private static final String VERTICAL_ALIGN_TEXT_TOP = "text-top";
+  private static final String VERTICAL_ALIGN_MIDDLE = "middle";
+  private static final String VERTICAL_ALIGN_BOTTOM = "bottom";
+  private static final String VERTICAL_ALIGN_TEXT_BOTTOM = "text-bottom";
+
+  private static final String VISIBILITY_HIDDEN = "hidden";
+  private static final String VISIBILITY_VISIBLE = "visible";
+
   protected Style() {
   }
 
   /**
+   * Clear the background-color css property.
+   */
+  public final void clearBackgroundColor() {
+     clearProperty(STYLE_BACKGROUND_COLOR);
+   }
+
+  /**
+   * Clear the background-image css property.
+   */
+  public final void clearBackgroundImage() {
+     clearProperty(STYLE_BACKGROUND_IMAGE);
+   }
+
+  /**
+   * Clear the border-color css property.
+   */
+  public final void clearBorderColor() {
+     clearProperty(STYLE_BORDER_COLOR);
+   }
+
+  /**
+   * Clears the border-style CSS property.
+   */
+  public final void clearBorderStyle() {
+    clearProperty(STYLE_BORDER_STYLE);
+  }
+
+  /**
+   * Clear the border-width css property.
+   */
+  public final void clearBorderWidth() {
+     clearProperty(STYLE_BORDER_WIDTH);
+   }
+
+  /**
+   * Clear the bottom css property.
+   */
+  public final void clearBottom() {
+     clearProperty(STYLE_BOTTOM);
+   }
+
+  /**
+   * Clear the color css property.
+   */
+  public final void clearColor() {
+     clearProperty(STYLE_COLOR);
+   }
+
+  /**
+   * Clears the cursor CSS property.
+   */
+  public final void clearCursor() {
+    clearProperty(STYLE_CURSOR);
+  }
+
+  /**
+   * Clears the display CSS property.
+   */
+  public final void clearDisplay() {
+    clearProperty(STYLE_DISPLAY);
+  }
+
+  /**
+   * Clear the font-size css property.
+   */
+  public final void clearFontSize() {
+     clearProperty(STYLE_FONT_SIZE);
+   }
+
+  /**
+   * Clears the font-style CSS property.
+   */
+  public final void clearFontStyle() {
+    clearProperty(STYLE_FONT_STYLE);
+  }
+
+  /**
+   * Clears the font-weight CSS property.
+   */
+  public final void clearFontWeight() {
+    clearProperty(STYLE_FONT_WEIGHT);
+  }
+
+  /**
+   * Clear the height css property.
+   */
+  public final void clearHeight() {
+     clearProperty(STYLE_HEIGHT);
+   }
+
+  /**
+   * Clear the left css property.
+   */
+  public final void clearLeft() {
+     clearProperty(STYLE_LEFT);
+   }
+
+  /**
+   * Clears the list-style-type CSS property.
+   */
+  public final void clearListStyleType() {
+    clearProperty(STYLE_LIST_STYLE_TYPE);
+  }
+
+  /**
+   * Clear the margin css property.
+   */
+  public final void clearMargin() {
+     clearProperty(STYLE_MARGIN);
+   }
+
+  /**
+   * Clear the margin-bottom css property.
+   */
+  public final void clearMarginBottom() {
+     clearProperty(STYLE_MARGIN_BOTTOM);
+   }
+
+  /**
+   * Clear the margin-left css property.
+   */
+  public final void clearMarginLeft() {
+     clearProperty(STYLE_MARGIN_LEFT);
+   }
+
+  /**
+   * Clear the margin-right css property.
+   */
+  public final void clearMarginRight() {
+     clearProperty(STYLE_MARGIN_RIGHT);
+   }
+
+  /**
+   * Clear the margin-top css property.
+   */
+  public final void clearMarginTop() {
+     clearProperty(STYLE_MARGIN_TOP);
+   }
+
+  /**
+   * Clear the opacity css property.
+   */
+  public final void clearOpacity() {
+     clearProperty(STYLE_OPACITY);
+   }
+
+  /**
+   * Clears the overflow CSS property.
+   */
+  public final void clearOverflow() {
+    clearProperty(STYLE_OVERFLOW);
+  }
+
+  /**
+   * Clear the padding css property.
+   */
+  public final void clearPadding() {
+     clearProperty(STYLE_PADDING);
+   }
+
+  /**
+   * Clear the padding-bottom css property.
+   */
+  public final void clearPaddingBottom() {
+     clearProperty(STYLE_PADDING_BOTTOM);
+   }
+
+  /**
+   * Clear the padding-left css property.
+   */
+  public final void clearPaddingLeft() {
+     clearProperty(STYLE_PADDING_LEFT);
+   }
+
+  /**
+   * Clear the padding-right css property.
+   */
+  public final void clearPaddingRight() {
+     clearProperty(STYLE_PADDING_RIGHT);
+   }
+
+  /**
+   * Clear the padding-top css property.
+   */
+  public final void clearPaddingTop() {
+     clearProperty(STYLE_PADDING_TOP);
+   }
+
+  /**
+   * Clears the position CSS property.
+   */
+  public final void clearPosition() {
+    clearProperty(STYLE_POSITION);
+  }
+
+  /**
+   * Clears the value of a named property, causing it to revert to its default.
+   */
+  public final void clearProperty(String name) {
+    setProperty(name, "");
+  }
+
+  /**
+   * Clear the right css property.
+   */
+  public final void clearRight() {
+     clearProperty(STYLE_RIGHT);
+   }
+
+  /**
+   * Clears the text-decoration CSS property.
+   */
+  public final void clearTextDecoration() {
+    clearProperty(STYLE_LIST_DECORATION);
+  }
+
+  /**
+   * Clear the top css property.
+   */
+  public final void clearTop() {
+     clearProperty(STYLE_TOP);
+   }
+
+  /**
+   * Clears the visibility CSS property.
+   */
+  public final void clearVisibility() {
+    clearProperty(STYLE_VISIBILITY);
+  }
+
+  /**
+   * Clear the width css property.
+   */
+  public final void clearWidth() {
+     clearProperty(STYLE_WIDTH);
+   }
+
+  /**
+   * Clear the z-index css property.
+   */
+  public final void clearZIndex() {
+     clearProperty(STYLE_Z_INDEX);
+   }
+
+  /**
+   * Get the background-color css property.
+   */
+  public final String getBackgroundColor() {
+    return getProperty(STYLE_BACKGROUND_COLOR);
+  }
+
+  /**
+   * Get the background-image css property.
+   */
+  public final String getBackgroundImage() {
+    return getProperty(STYLE_BACKGROUND_IMAGE);
+  }
+
+  /**
+   * Get the border-color css property.
+   */
+  public final String getBorderColor() {
+    return getProperty(STYLE_BORDER_COLOR);
+  }
+
+  /**
+   * Gets the border-style CSS property.
+   */
+  public final String getBorderStyle() {
+    return getProperty(STYLE_BORDER_STYLE);
+  }
+
+  /**
+   * Get the border-width css property.
+   */
+  public final String getBorderWidth() {
+    return getProperty(STYLE_BORDER_WIDTH);
+  }
+
+  /**
+   * Get the bottom css property.
+   */
+  public final String getBottom() {
+    return getProperty(STYLE_BOTTOM);
+  }
+
+  /**
+   * Get the color css property.
+   */
+  public final String getColor() {
+    return getProperty(STYLE_COLOR);
+  }
+
+  /**
+   * Gets the cursor CSS property.
+   */
+  public final String getCursor() {
+    return getProperty(STYLE_CURSOR);
+  }
+
+  /**
+   * Gets the display CSS property.
+   */
+  public final String getDisplay() {
+    return getProperty(STYLE_DISPLAY);
+  }
+
+  /**
+   * Get the font-size css property.
+   */
+  public final String getFontSize() {
+    return getProperty(STYLE_FONT_SIZE);
+  }
+
+  /**
+   * Gets the font-style CSS property.
+   */
+  public final String getFontStyle() {
+    return getProperty(STYLE_FONT_STYLE);
+  }
+
+  /**
+   * Gets the font-weight CSS property.
+   */
+  public final String getFontWeight() {
+    return getProperty(STYLE_FONT_WEIGHT);
+  }
+
+  /**
+   * Get the height css property.
+   */
+  public final String getHeight() {
+    return getProperty(STYLE_HEIGHT);
+  }
+
+  /**
+   * Get the left css property.
+   */
+  public final String getLeft() {
+    return getProperty(STYLE_LEFT);
+  }
+
+  /**
+   * Gets the list-style-type CSS property.
+   */
+  public final String getListStyleType() {
+    return getProperty(STYLE_LIST_STYLE_TYPE);
+  }
+
+  /**
+   * Get the margin css property.
+   */
+  public final String getMargin() {
+    return getProperty(STYLE_MARGIN);
+  }
+
+  /**
+   * Get the margin-bottom css property.
+   */
+  public final String getMarginBottom() {
+    return getProperty(STYLE_MARGIN_BOTTOM);
+  }
+
+  /**
+   * Get the margin-left css property.
+   */
+  public final String getMarginLeft() {
+    return getProperty(STYLE_MARGIN_LEFT);
+  }
+
+  /**
+   * Get the margin-right css property.
+   */
+  public final String getMarginRight() {
+    return getProperty(STYLE_MARGIN_RIGHT);
+  }
+
+  /**
+   * Get the margin-top css property.
+   */
+  public final String getMarginTop() {
+    return getProperty(STYLE_MARGIN_TOP);
+  }
+
+  /**
+   * Get the opacity css property.
+   */
+  public final String getOpacity() {
+    return getProperty(STYLE_OPACITY);
+  }
+
+  /**
+   * Gets the overflow CSS property.
+   */
+  public final String getOverflow() {
+    return getProperty(STYLE_OVERFLOW);
+  }
+
+  /**
+   * Get the padding css property.
+   */
+  public final String getPadding() {
+    return getProperty(STYLE_PADDING);
+  }
+
+  /**
+   * Get the padding-bottom css property.
+   */
+  public final String getPaddingBottom() {
+    return getProperty(STYLE_PADDING_BOTTOM);
+  }
+
+  /**
+   * Get the padding-left css property.
+   */
+  public final String getPaddingLeft() {
+    return getProperty(STYLE_PADDING_LEFT);
+  }
+
+  /**
+   * Get the padding-right css property.
+   */
+  public final String getPaddingRight() {
+    return getProperty(STYLE_PADDING_RIGHT);
+  }
+
+  /**
+   * Get the padding-top css property.
+   */
+  public final String getPaddingTop() {
+    return getProperty(STYLE_PADDING_TOP);
+  }
+
+  /**
+   * Gets the position CSS property.
+   */
+  public final String getPosition() {
+    return getProperty(STYLE_POSITION);
+  }
+
+  /**
    * Gets the value of a named property.
    */
   public final String getProperty(String name) {
@@ -36,6 +1055,244 @@
   }
 
   /**
+   * Get the right css property.
+   */
+  public final String getRight() {
+    return getProperty(STYLE_RIGHT);
+  }
+
+  /**
+   * Gets the text-decoration CSS property.
+   */
+  public final String getTextDecoration() {
+    return getProperty(STYLE_LIST_DECORATION);
+  }
+
+  /**
+   * Get the top css property.
+   */
+  public final String getTop() {
+    return getProperty(STYLE_TOP);
+  }
+
+  /**
+   * Gets the vertical-align CSS property.
+   */
+  public final String getVerticalAlign() {
+    return getProperty(STYLE_VERTICAL_ALIGN);
+  }
+
+  /**
+   * Gets the visibility CSS property.
+   */
+  public final String getVisibility() {
+    return getProperty(STYLE_VISIBILITY);
+  }
+
+  /**
+   * Get the width css property.
+   */
+  public final String getWidth() {
+    return getProperty(STYLE_WIDTH);
+  }
+
+  /**
+   * Get the z-index css property.
+   */
+  public final String getZIndex() {
+    return getProperty(STYLE_Z_INDEX);
+  }
+
+  /**
+   * Set the background-color css property.
+   */
+  public final void setBackgroundColor(String value) {
+    setProperty(STYLE_BACKGROUND_COLOR, value);
+  }
+
+  /**
+   * Set the background-image css property.
+   */
+  public final void setBackgroundImage(String value) {
+    setProperty(STYLE_BACKGROUND_IMAGE, value);
+  }
+
+  /**
+   * Set the border-color css property.
+   */
+  public final void setBorderColor(String value) {
+    setProperty(STYLE_BORDER_COLOR, value);
+  }
+
+  /**
+   * Sets the border-style CSS property.
+   */
+  public final void setBorderStyle(BorderStyle value) {
+    setProperty(STYLE_BORDER_STYLE, value.getCssName());
+  }
+
+  /**
+   * Set the border-width css property.
+   */
+  public final void setBorderWidth(double value, Unit unit) {
+    setProperty(STYLE_BORDER_WIDTH, value, unit);
+  }
+
+  /**
+   * Set the bottom css property.
+   */
+  public final void setBottom(double value, Unit unit) {
+    setProperty(STYLE_BOTTOM, value, unit);
+  }
+
+  /**
+   * Sets the cursor CSS property.
+   */
+  public final void setCursor(Cursor value) {
+    setProperty(STYLE_CURSOR, value.getCssName());
+  }
+
+  /**
+   * Sets the display CSS property.
+   */
+  public final void setDisplay(Display value) {
+    setProperty(STYLE_DISPLAY, value.getCssName());
+  }
+
+  /**
+   * Set the font-size css property.
+   */
+  public final void setFontSize(double value, Unit unit) {
+    setProperty(STYLE_FONT_SIZE, value, unit);
+  }
+
+  /**
+   * Sets the font-style CSS property.
+   */
+  public final void setFontStyle(FontStyle value) {
+    setProperty(STYLE_FONT_STYLE, value.getCssName());
+  }
+
+  /**
+   * Sets the font-weight CSS property.
+   */
+  public final void setFontWeight(FontWeight value) {
+    setProperty(STYLE_FONT_WEIGHT, value.getCssName());
+  }
+
+  /**
+   * Set the height css property.
+   */
+  public final void setHeight(double value, Unit unit) {
+    setProperty(STYLE_HEIGHT, value, unit);
+  }
+
+  /**
+   * Set the left css property.
+   */
+  public final void setLeft(double value, Unit unit) {
+    setProperty(STYLE_LEFT, value, unit);
+  }
+
+  /**
+   * Sets the list-style-type CSS property.
+   */
+  public final void setListStyleType(ListStyleType value) {
+    setProperty(STYLE_LIST_STYLE_TYPE, value.getCssName());
+  }
+
+  /**
+   * Set the margin css property.
+   */
+  public final void setMargin(double value, Unit unit) {
+    setProperty(STYLE_MARGIN, value, unit);
+  }
+
+  /**
+   * Set the margin-bottom css property.
+   */
+  public final void setMarginBottom(double value, Unit unit) {
+    setProperty(STYLE_MARGIN_BOTTOM, value, unit);
+  }
+
+  /**
+   * Set the margin-left css property.
+   */
+  public final void setMarginLeft(double value, Unit unit) {
+    setProperty(STYLE_MARGIN_LEFT, value, unit);
+  }
+
+  /**
+   * Set the margin-right css property.
+   */
+  public final void setMarginRight(double value, Unit unit) {
+    setProperty(STYLE_MARGIN_RIGHT, value, unit);
+  }
+
+  /**
+   * Set the margin-top css property.
+   */
+  public final void setMarginTop(double value, Unit unit) {
+    setProperty(STYLE_MARGIN_TOP, value, unit);
+  }
+
+  /**
+   * Set the opacity css property.
+   */
+  public final void setOpacity(double value) {
+    setProperty(STYLE_OPACITY, value + "");
+  }
+
+  /**
+   * Sets the overflow CSS property.
+   */
+  public final void setOverflow(Overflow value) {
+    setProperty(STYLE_OVERFLOW, value.getCssName());
+  }
+
+  /**
+   * Set the padding css property.
+   */
+  public final void setPadding(double value, Unit unit) {
+    setProperty(STYLE_PADDING, value, unit);
+  }
+
+  /**
+   * Set the padding-bottom css property.
+   */
+  public final void setPaddingBottom(double value, Unit unit) {
+    setProperty(STYLE_PADDING_BOTTOM, value, unit);
+  }
+
+  /**
+   * Set the padding-left css property.
+   */
+  public final void setPaddingLeft(double value, Unit unit) {
+    setProperty(STYLE_PADDING_LEFT, value, unit);
+  }
+
+  /**
+   * Set the padding-right css property.
+   */
+  public final void setPaddingRight(double value, Unit unit) {
+    setProperty(STYLE_PADDING_RIGHT, value, unit);
+  }
+
+  /**
+   * Set the padding-top css property.
+   */
+  public final void setPaddingTop(double value, Unit unit) {
+    setProperty(STYLE_PADDING_TOP, value, unit);
+  }
+
+  /**
+   * Sets the position CSS property.
+   */
+  public final void setPosition(Position value) {
+    setProperty(STYLE_POSITION, value.getCssName());
+  }
+
+  /**
    * Sets the value of a named property.
    */
   public final void setProperty(String name, String value) {
@@ -44,13 +1301,76 @@
   }
 
   /**
+   * Sets the value of a named property in the specified units.
+   */
+  public final void setProperty(String name, double value, Unit unit) {
+    assertCamelCase(name);
+    setPropertyImpl(name, value + unit.getType());
+  }
+
+  /**
    * Sets the value of a named property, in pixels.
    * 
    * This is shorthand for <code>value + "px"</code>.
    */
   public final void setPropertyPx(String name, int value) {
-    assertCamelCase(name);
-    setPropertyPxImpl(name, value);
+    setProperty(name, value, Unit.PX);
+  }
+
+  /**
+   * Set the right css property.
+   */
+  public final void setRight(double value, Unit unit) {
+    setProperty(STYLE_RIGHT, value, unit);
+  }
+
+  /**
+   * Sets the text-decoration CSS property.
+   */
+  public final void setTextDecoration(TextDecoration value) {
+    setProperty(STYLE_LIST_DECORATION, value.getCssName());
+  }
+
+  /**
+   * Set the top css property.
+   */
+  public final void setTop(double value, Unit unit) {
+    setProperty(STYLE_TOP, value, unit);
+  }
+
+  /**
+   * Sets the vertical-align CSS property.
+   */
+  public final void setVerticalAlign(VerticalAlign value) {
+    setProperty(STYLE_VERTICAL_ALIGN, value.getCssName());
+  }
+
+  /**
+   * Sets the vertical-align CSS property.
+   */
+  public final void setVerticalAlign(double value, Unit unit) {
+    setProperty(STYLE_VERTICAL_ALIGN, value, unit);
+  }
+
+  /**
+   * Sets the visibility CSS property.
+   */
+  public final void setVisibility(Visibility value) {
+    setProperty(STYLE_VISIBILITY, value.getCssName());
+  }
+
+  /**
+   * Set the width css property.
+   */
+  public final void setWidth(double value, Unit unit) {
+    setProperty(STYLE_WIDTH, value, unit);
+  }
+
+  /**
+   * Set the z-index css property.
+   */
+  public final void setZIndex(int value) {
+    setProperty(STYLE_Z_INDEX, value + "");
   }
 
   /**
@@ -67,22 +1387,13 @@
    * Gets the value of a named property.
    */
   private native String getPropertyImpl(String name) /*-{
-     return this[name];
-   }-*/;
+    return this[name];
+  }-*/;
 
   /**
    * Sets the value of a named property.
    */
   private native void setPropertyImpl(String name, String value) /*-{
-     this[name] = value;
-   }-*/;
-
-  /**
-   * Sets the value of a named property, in pixels.
-   * 
-   * This is shorthand for <code>value + "px"</code>.
-   */
-  private native void setPropertyPxImpl(String name, int value) /*-{
-     this[name] = value + "px";
-   }-*/;
+    this[name] = value;
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/dom/client/Text.java b/user/src/com/google/gwt/dom/client/Text.java
index 61b4df9..9bf75e2 100644
--- a/user/src/com/google/gwt/dom/client/Text.java
+++ b/user/src/com/google/gwt/dom/client/Text.java
@@ -33,6 +33,13 @@
   }
 
   /**
+   * Deletes data at the given [offset, length] range.
+   */
+  public final native void deleteData(int offset, int length) /*-{
+    this.deleteData(offset, length);
+  }-*/;
+
+  /**
    * The character data of this text node.
    */
   public final native String getData() /*-{
@@ -47,9 +54,32 @@
   }-*/;
 
   /**
+   * Inserts character data at the given offset.
+   */
+  public final native void insertData(int offset, String data) /*-{
+    this.insertData(offset, data);
+  }-*/;
+
+  /**
+   * Replaces data at the given [offset, length] range with the given string.
+   */
+  public final native void replaceData(int offset, int length, String data) /*-{
+    this.replaceData(offset, length, data);
+  }-*/;
+
+  /**
    * The character data of this text node.
    */
   public final native void setData(String data) /*-{
     this.data = data;
   }-*/;
+
+  /**
+   * Splits the data in this node into two separate text nodes. The text
+   * before the split offset is kept in this node, and a new sibling node is
+   * created to contain the text after the offset.
+   */
+  public final native Text splitText(int offset) /*-{
+    return this.splitText(offset);
+  }-*/;
 }
diff --git a/user/src/com/google/gwt/user/client/ui/UIObject.java b/user/src/com/google/gwt/user/client/ui/UIObject.java
index 32b3df6..f9431a4 100644
--- a/user/src/com/google/gwt/user/client/ui/UIObject.java
+++ b/user/src/com/google/gwt/user/client/ui/UIObject.java
@@ -251,54 +251,10 @@
       throw new IllegalArgumentException(EMPTY_STYLENAME_MSG);
     }
 
-    // Get the current style string.
-    String oldStyle = getStyleName(elem);
-    int idx = oldStyle.indexOf(style);
-
-    // Calculate matching index.
-    while (idx != -1) {
-      if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') {
-        int last = idx + style.length();
-        int lastPos = oldStyle.length();
-        if ((last == lastPos)
-            || ((last < lastPos) && (oldStyle.charAt(last) == ' '))) {
-          break;
-        }
-      }
-      idx = oldStyle.indexOf(style, idx + 1);
-    }
-
     if (add) {
-      // Only add the style if it's not already present.
-      if (idx == -1) {
-        if (oldStyle.length() > 0) {
-          oldStyle += " ";
-        }
-        DOM.setElementProperty(
-            elem.<com.google.gwt.user.client.Element> cast(), "className",
-            oldStyle + style);
-      }
+      elem.addClassName(style);
     } else {
-      // Don't try to remove the style if it's not there.
-      if (idx != -1) {
-        // Get the leading and trailing parts, without the removed name.
-        String begin = oldStyle.substring(0, idx).trim();
-        String end = oldStyle.substring(idx + style.length()).trim();
-
-        // Some contortions to make sure we don't leave extra spaces.
-        String newClassName;
-        if (begin.length() == 0) {
-          newClassName = end;
-        } else if (end.length() == 0) {
-          newClassName = begin;
-        } else {
-          newClassName = begin + " " + end;
-        }
-
-        DOM.setElementProperty(
-            elem.<com.google.gwt.user.client.Element> cast(), "className",
-            newClassName);
-      }
+      elem.removeClassName(style);
     }
   }
 
diff --git a/user/test/com/google/gwt/dom/DOMSuite.java b/user/test/com/google/gwt/dom/DOMSuite.java
index b0c0dcf..409bab7 100644
--- a/user/test/com/google/gwt/dom/DOMSuite.java
+++ b/user/test/com/google/gwt/dom/DOMSuite.java
@@ -22,7 +22,9 @@
 import com.google.gwt.dom.client.NodeTest;
 import com.google.gwt.dom.client.SelectTests;
 import com.google.gwt.dom.client.StyleInjectorTest;
+import com.google.gwt.dom.client.StyleTest;
 import com.google.gwt.dom.client.TableTests;
+import com.google.gwt.dom.client.TextTest;
 import com.google.gwt.junit.tools.GWTTestSuite;
 
 import junit.framework.Test;
@@ -41,8 +43,10 @@
     suite.addTestSuite(FormTests.class);
     suite.addTestSuite(MapTests.class);
     suite.addTestSuite(SelectTests.class);
+    suite.addTestSuite(StyleTest.class);
     suite.addTestSuite(StyleInjectorTest.class);
     suite.addTestSuite(TableTests.class);
+    suite.addTestSuite(TextTest.class);
 
     return suite;
   }
diff --git a/user/test/com/google/gwt/dom/client/ElementTest.java b/user/test/com/google/gwt/dom/client/ElementTest.java
index a3e8f7e..d120800 100644
--- a/user/test/com/google/gwt/dom/client/ElementTest.java
+++ b/user/test/com/google/gwt/dom/client/ElementTest.java
@@ -15,7 +15,7 @@
  */
 package com.google.gwt.dom.client;
 
-import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DeferredCommand;
@@ -30,6 +30,43 @@
     return "com.google.gwt.dom.DOMTest";
   }
 
+  public void testAddRemoveReplaceClassName() {
+    DivElement div = Document.get().createDivElement();
+
+    div.setClassName("foo");
+    assertEquals("foo", div.getClassName());
+
+    div.addClassName("bar");
+    assertEquals("foo bar", div.getClassName());
+
+    div.addClassName("baz");
+    assertEquals("foo bar baz", div.getClassName());
+
+    div.replaceClassName("bar", "tintin");
+    assertTrue(div.getClassName().contains("tintin"));
+    assertFalse(div.getClassName().contains("bar"));
+  }
+
+  /**
+   * firstChildElement, nextSiblingElement.
+   */
+  public void testChildElements() {
+    Document doc = Document.get();
+    DivElement parent = doc.createDivElement();
+    DivElement div0 = doc.createDivElement();
+    DivElement div1 = doc.createDivElement();
+
+    parent.appendChild(doc.createTextNode("foo"));
+    parent.appendChild(div0);
+    parent.appendChild(doc.createTextNode("bar"));
+    parent.appendChild(div1);
+
+    Element fc = parent.getFirstChildElement();
+    Element ns = fc.getNextSiblingElement();
+    assertEquals(div0, fc);
+    assertEquals(div1, ns);
+  }
+
   /**
    * [get|set|remove]Attribute.
    */
@@ -57,8 +94,59 @@
     Document.get().getBody().removeChild(div);
   }
 
+  public void testEmptyClassNameAssertion() {
+    DivElement div = Document.get().createDivElement();
+
+    if (getClass().desiredAssertionStatus()) {
+      div.setClassName("primary");
+      try {
+        div.addClassName("");
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      try {
+        div.addClassName(" ");
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      try {
+        div.addClassName(null);
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      try {
+        div.removeClassName("");
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      try {
+        div.removeClassName(" ");
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      try {
+        div.removeClassName(null);
+        fail();
+      } catch (AssertionError e) {
+        // This *should* throw.
+      }
+
+      assertEquals("primary", div.getClassName());
+    }
+  }
+
   /**
-   * getAbsolute[Left|Top].
+   * getAbsolute[Left|Top|Right|Bottom].
    */
   public void testGetAbsolutePosition() {
     final int border = 8;
@@ -67,8 +155,10 @@
 
     final int top = 15;
     final int left = 14;
+    final int width = 128;
+    final int height = 64;
 
-    Document doc = Document.get();
+    final Document doc = Document.get();
     final DivElement elem = doc.createDivElement();
     doc.getBody().appendChild(elem);
 
@@ -79,17 +169,38 @@
 
     elem.getStyle().setPropertyPx("top", top - doc.getBodyOffsetLeft());
     elem.getStyle().setPropertyPx("left", left - doc.getBodyOffsetTop());
+    elem.getStyle().setPropertyPx("width", width);
+    elem.getStyle().setPropertyPx("height", height);
 
-    delayTestFinish(1000);
     DeferredCommand.addCommand(new Command() {
       public void execute() {
-        assertEquals(top + margin, elem.getAbsoluteTop());
-        assertEquals(left + margin, elem.getAbsoluteLeft());
-        finishTest();
+        int absLeft = left + margin;
+        int absTop = top + margin;
+        int interiorDecorations = (border * 2) + (padding * 2);
+
+        assertEquals(absLeft, elem.getAbsoluteLeft());
+        assertEquals(absTop, elem.getAbsoluteTop());
+
+        if (isIE() && !doc.isCSS1Compat()) {
+          // In IE/quirk, the interior decorations are considered part of the
+          // width/height, so there's no need to account for them here.
+          assertEquals(absLeft + width, elem.getAbsoluteRight());
+          assertEquals(absTop + height, elem.getAbsoluteBottom());
+        } else {
+          assertEquals(absLeft + width + interiorDecorations,
+              elem.getAbsoluteRight());
+          assertEquals(absTop + height + interiorDecorations,
+              elem.getAbsoluteBottom());
+        }
       }
     });
   }
 
+  private native boolean isIE() /*-{
+    var ua = navigator.userAgent.toLowerCase();
+    return ua.indexOf("msie") != -1;
+  }-*/;
+
   /**
    * scroll[Left|Top], scrollIntoView.
    */
@@ -125,6 +236,152 @@
   }
 
   /**
+   * getElementsByTagName.
+   */
+  public void testGetElementsByTagName() {
+    DivElement div = Document.get().createDivElement();
+    div.setInnerHTML("<span><button>foo</button><span><button>bar</button></span></span>");
+
+    NodeList<Element> nodes = div.getElementsByTagName("button");
+    assertEquals(2, nodes.getLength());
+    assertEquals("foo", nodes.getItem(0).getInnerText());
+    assertEquals("bar", nodes.getItem(1).getInnerText());
+  }
+
+  public void testHasAttribute() {
+    DivElement div = Document.get().createDivElement();
+
+    // Assert that a raw element doesn't incorrectly report that it has any
+    // unspecified built-in attributes (this is a problem on IE<8 if you're not
+    // careful in implementing hasAttribute()).
+    assertFalse(div.hasAttribute("class"));
+    assertFalse(div.hasAttribute("style"));
+    assertFalse(div.hasAttribute("title"));
+    assertFalse(div.hasAttribute("id"));
+
+    // Ensure that setting HTML-defined attributes is properly reported by
+    // hasAttribute().
+    div.setId("foo");
+    assertTrue(div.hasAttribute("id"));
+
+    // Ensure that setting *custom* attributes is properly reported by
+    // hasAttribute().
+    assertFalse(div.hasAttribute("foo"));
+    div.setAttribute("foo", "bar");
+    assertTrue(div.hasAttribute("foo"));
+
+    // Ensure that a null attribute argument always returns null.
+    assertFalse(div.hasAttribute(null));
+  }
+
+  /**
+   * Tests HeadingElement.as() (it has slightly more complex assertion logic
+   * than most).
+   */
+  public void testHeadingElementAs() {
+    DivElement placeHolder = Document.get().createDivElement();
+
+    for (int i = 0; i < 6; ++i) {
+      placeHolder.setInnerHTML("<H" + (i + 1) + "/>");
+      assertNotNull(HeadingElement.as(placeHolder.getFirstChildElement()));
+    }
+
+    if (getClass().desiredAssertionStatus()) {
+      Element notHeading = Document.get().createDivElement();
+      try {
+        HeadingElement.as(notHeading);
+        fail("Expected assertion failure");
+      } catch (AssertionError e) {
+        // this *should* happen.
+      }
+    }
+  }
+
+  /**
+   * Document.createElement('ns:tag'), getTagName().
+   */
+  public void testNamespaces() {
+    Element elem = Document.get().createElement("myns:elem");
+    assertEquals("myns:elem", elem.getTagName().toLowerCase());
+  }
+
+  /**
+   * className, id, tagName, title, dir, lang.
+   */
+  public void testNativeProperties() {
+    DivElement div = Document.get().createDivElement();
+
+    assertEquals("div", div.getTagName().toLowerCase());
+
+    div.setClassName("myClass");
+    assertEquals(div.getClassName(), "myClass");
+
+    div.setId("myId");
+    assertEquals(div.getId(), "myId");
+
+    div.setTitle("myTitle");
+    assertEquals(div.getTitle(), "myTitle");
+
+    div.setDir("rtl");
+    assertEquals(div.getDir(), "rtl");
+
+    div.setLang("fr-FR");
+    assertEquals(div.getLang(), "fr-FR");
+  }
+
+  /**
+   * offset[Left|Top|Width|Height], offsetParent.
+   */
+  public void testOffsets() {
+    DivElement outer = Document.get().createDivElement();
+    DivElement middle = Document.get().createDivElement();
+    DivElement inner = Document.get().createDivElement();
+
+    Document.get().getBody().appendChild(outer);
+    outer.appendChild(middle);
+    middle.appendChild(inner);
+
+    outer.getStyle().setProperty("position", "absolute");
+    inner.getStyle().setProperty("position", "relative");
+    inner.getStyle().setPropertyPx("left", 19);
+    inner.getStyle().setPropertyPx("top", 23);
+    inner.getStyle().setPropertyPx("width", 29);
+    inner.getStyle().setPropertyPx("height", 31);
+
+    assertEquals(outer, inner.getOffsetParent());
+    assertEquals(19, inner.getOffsetLeft());
+    assertEquals(23, inner.getOffsetTop());
+    assertEquals(29, inner.getOffsetWidth());
+    assertEquals(31, inner.getOffsetHeight());
+  }
+
+  /**
+   * setProperty*, getProperty*.
+   */
+  public void testProperties() {
+    DivElement div = Document.get().createDivElement();
+
+    div.setPropertyString("foo", "bar");
+    assertEquals("bar", div.getPropertyString("foo"));
+
+    div.setPropertyInt("foo", 42);
+    assertEquals(42, div.getPropertyInt("foo"));
+
+    div.setPropertyBoolean("foo", true);
+    div.setPropertyBoolean("bar", false);
+    assertEquals(true, div.getPropertyBoolean("foo"));
+    assertEquals(false, div.getPropertyBoolean("bar"));
+
+    Object obj = new Object();
+    div.setPropertyObject("baz", obj);
+    assertEquals(obj, div.getPropertyObject("baz"));
+
+    JavaScriptObject jso = createTrivialJSO();
+    div.setPropertyJSO("tintin", jso);
+    assertEquals(jso, div.getPropertyJSO("tintin"));
+  }
+
+  /**
    * Tests that scrollLeft behaves as expected in RTL mode.
    */
   public void testScrollLeftInRtl() {
@@ -171,63 +428,18 @@
   }
 
   /**
-   * getParentElement.
+   * innerHTML.
    */
-  public void testGetParent() {
-    Element element = Document.get().getBody();
-    int i = 0;
-    while (i < 10 && element != null) {
-      element = element.getParentElement();
-      i++;
-    }
-
-    // If we got here we looped "forever" or passed, as no exception was thrown.
-    if (i == 10) {
-      fail("Cyclic parent structure detected.");
-    }
-
-    // If we get here, we pass, because we encountered no errors going to the
-    // top of the parent hierarchy.
-  }
-
-  /**
-   * firstChildElement, nextSiblingElement.
-   */
-  public void testChildElements() {
-    Document doc = Document.get();
-    DivElement parent = doc.createDivElement();
-    DivElement div0 = doc.createDivElement();
-    DivElement div1 = doc.createDivElement();
-
-    parent.appendChild(doc.createTextNode("foo"));
-    parent.appendChild(div0);
-    parent.appendChild(doc.createTextNode("bar"));
-    parent.appendChild(div1);
-
-    Element fc = parent.getFirstChildElement();
-    Element ns = fc.getNextSiblingElement();
-    assertEquals(div0, fc);
-    assertEquals(div1, ns);
-  }
-
-  /**
-   * isOrHasChild.
-   */
-  public void testIsOrHasChild() {
+  public void testSetInnerHTML() {
     DivElement div = Document.get().createDivElement();
-    DivElement childDiv = Document.get().createDivElement();
+    div.setInnerHTML("<button><img src='foo.gif'></button>");
 
-    assertFalse(div.isOrHasChild(childDiv));
-    assertTrue(div.isOrHasChild(div));
+    Element button = div.getFirstChildElement();
+    Element img = button.getFirstChildElement();
 
-    div.appendChild(childDiv);
-    assertTrue(div.isOrHasChild(childDiv));
-    assertFalse(childDiv.isOrHasChild(div));
-
-    Document.get().getBody().appendChild(div);
-    assertTrue(div.isOrHasChild(childDiv));
-    assertTrue(div.isOrHasChild(div));
-    assertFalse(childDiv.isOrHasChild(div));
+    assertEquals("button", button.getTagName().toLowerCase());
+    assertEquals("img", img.getTagName().toLowerCase());
+    assertTrue(((ImageElement) img).getSrc().endsWith("foo.gif"));
   }
 
   /**
@@ -258,63 +470,6 @@
   }
 
   /**
-   * innerHTML.
-   */
-  public void testSetInnerHTML() {
-    DivElement div = Document.get().createDivElement();
-    div.setInnerHTML("<button><img src='foo.gif'></button>");
-
-    Element button = div.getFirstChildElement();
-    Element img = button.getFirstChildElement();
-
-    assertEquals("button", button.getTagName().toLowerCase());
-    assertEquals("img", img.getTagName().toLowerCase());
-    assertTrue(((ImageElement) img).getSrc().endsWith("foo.gif"));
-  }
-
-  /**
-   * setProperty*, getProperty*.
-   */
-  public void testProperties() {
-    DivElement div = Document.get().createDivElement();
-
-    div.setPropertyString("foo", "bar");
-    assertEquals("bar", div.getPropertyString("foo"));
-
-    div.setPropertyInt("foo", 42);
-    assertEquals(42, div.getPropertyInt("foo"));
-
-    div.setPropertyBoolean("foo", true);
-    div.setPropertyBoolean("bar", false);
-    assertEquals(true, div.getPropertyBoolean("foo"));
-    assertEquals(false, div.getPropertyBoolean("bar"));
-  }
-
-  /**
-   * className, id, tagName, title, dir, lang.
-   */
-  public void testNativeProperties() {
-    DivElement div = Document.get().createDivElement();
-
-    assertEquals("div", div.getTagName().toLowerCase());
-
-    div.setClassName("myClass");
-    assertEquals(div.getClassName(), "myClass");
-
-    div.setId("myId");
-    assertEquals(div.getId(), "myId");
-
-    div.setTitle("myTitle");
-    assertEquals(div.getTitle(), "myTitle");
-
-    div.setDir("rtl");
-    assertEquals(div.getDir(), "rtl");
-
-    div.setLang("fr-FR");
-    assertEquals(div.getLang(), "fr-FR");
-  }
-
-  /**
    * style.
    */
   public void testStyle() {
@@ -362,65 +517,7 @@
     }
   }
 
-  /**
-   * offset[Left|Top|Width|Height], offsetParent.
-   */
-  public void testOffsets() {
-    DivElement outer = Document.get().createDivElement();
-    DivElement middle = Document.get().createDivElement();
-    DivElement inner = Document.get().createDivElement();
-
-    Document.get().getBody().appendChild(outer);
-    outer.appendChild(middle);
-    middle.appendChild(inner);
-
-    outer.getStyle().setProperty("position", "absolute");
-    inner.getStyle().setProperty("position", "relative");
-    inner.getStyle().setPropertyPx("left", 19);
-    inner.getStyle().setPropertyPx("top", 23);
-    inner.getStyle().setPropertyPx("width", 29);
-    inner.getStyle().setPropertyPx("height", 31);
-
-    assertEquals(outer, inner.getOffsetParent());
-    assertEquals(19, inner.getOffsetLeft());
-    assertEquals(23, inner.getOffsetTop());
-    assertEquals(29, inner.getOffsetWidth());
-    assertEquals(31, inner.getOffsetHeight());
-  }
-
-  /**
-   * getElementsByTagName.
-   */
-  public void testGetElementsByTagName() {
-    DivElement div = Document.get().createDivElement();
-    div.setInnerHTML("<span><button>foo</button><span><button>bar</button></span></span>");
-
-    NodeList<Element> nodes = div.getElementsByTagName("button");
-    assertEquals(2, nodes.getLength());
-    assertEquals("foo", nodes.getItem(0).getInnerText());
-    assertEquals("bar", nodes.getItem(1).getInnerText());
-  }
-
-  /**
-   * Tests HeadingElement.as() (it has slightly more complex assertion logic
-   * than most).
-   */
-  public void testHeadingElementAs() {
-    DivElement placeHolder = Document.get().createDivElement();
-
-    for (int i = 0; i < 6; ++i) {
-      placeHolder.setInnerHTML("<H" + (i + 1) + "/>");
-      assertNotNull(HeadingElement.as(placeHolder.getFirstChildElement()));
-    }
-
-    if (!GWT.isScript()) {
-      Element notHeading = Document.get().createDivElement();
-      try {
-        HeadingElement.as(notHeading);
-        fail("Expected assertion failure");
-      } catch (AssertionError e) {
-        // this *should* happen.
-      }
-    }
-  }
+  private native JavaScriptObject createTrivialJSO() /*-{
+    return {};
+  }-*/;
 }
diff --git a/user/test/com/google/gwt/dom/client/NodeTest.java b/user/test/com/google/gwt/dom/client/NodeTest.java
index 3aa2c5b..7fe178b 100644
--- a/user/test/com/google/gwt/dom/client/NodeTest.java
+++ b/user/test/com/google/gwt/dom/client/NodeTest.java
@@ -28,16 +28,165 @@
   }
 
   /**
-   * nodeType
+   * appendChild, insertBefore, removeChild, replaceChild
    */
-  public void testNodeType() {
+  public void testAppendRemoveReplace() {
     Document doc = Document.get();
+    BodyElement body = doc.getBody();
+
+    // <div>foo<button/>bar</div>
     DivElement div = doc.createDivElement();
     Text txt0 = doc.createTextNode("foo");
+    ButtonElement btn0 = doc.createButtonElement();
+    Text txt1 = doc.createTextNode("bar");
 
-    assertEquals(Node.DOCUMENT_NODE, doc.getNodeType());
-    assertEquals(Node.ELEMENT_NODE, div.getNodeType());
-    assertEquals(Node.TEXT_NODE, txt0.getNodeType());
+    body.appendChild(div);
+    div.appendChild(txt0);
+    div.appendChild(btn0);
+    div.appendChild(txt1);
+
+    // appendChild, insertBefore
+    ButtonElement btn1 = doc.createButtonElement();
+
+    // <div>foo<btn0/>bar<btn1/></div>
+    div.appendChild(btn1);
+    assertEquals(btn1, div.getLastChild());
+
+    // <div>foo<button/>bar<button/></div>
+    div.insertBefore(btn1, txt1);
+    assertEquals(4, div.getChildNodes().getLength());
+    assertEquals(btn1, div.getChildNodes().getItem(2));
+
+    // removeChild
+    // <div>foo<btn0/>bar</div> (back to original)
+    div.removeChild(btn1);
+    assertEquals(3, div.getChildNodes().getLength());
+
+    // replaceChild
+    // <div>foo<btn1/>bar</div>
+    div.replaceChild(btn1, btn0);
+    assertEquals(btn1, txt0.getNextSibling());
+    assertEquals(btn1, txt1.getPreviousSibling());
+
+    // insertAfter
+    // <div>foo<btn1/><btn0/>bar</div>
+    div.insertAfter(btn0, btn1);
+    assertEquals(btn0, btn1.getNextSibling());
+
+    // insertFirst
+    // <div><btn1/>foo<btn0/>bar</div>
+    div.insertFirst(btn1);
+    assertEquals(btn1, div.getFirstChild());
+    
+    // removeFromParent
+    // <div>foo<btn0/>bar</div>
+    btn1.removeFromParent();
+    assertNull(btn1.getParentElement());
+    assertEquals(txt0, div.getFirstChild());
+  }
+
+  /**
+   * setAttribute, getAttribute, hasAttributes, hasAttribute
+   */
+  public void testAttributes() {
+    Document doc = Document.get();
+    DivElement div = doc.createDivElement();
+
+    div.setAttribute("id", "myId");
+    assertEquals("myId", div.getAttribute("id"));
+  }
+
+  /**
+   * childNodes, hasChildNodes
+   */
+  public void testChildNodeList() {
+    Document doc = Document.get();
+    BodyElement body = doc.getBody();
+
+    // <div>foo<button/>bar</div>
+    DivElement div = doc.createDivElement();
+    Text txt0 = doc.createTextNode("foo");
+    ButtonElement btn0 = doc.createButtonElement();
+    Text txt1 = doc.createTextNode("bar");
+
+    body.appendChild(div);
+    div.appendChild(txt0);
+    div.appendChild(btn0);
+    div.appendChild(txt1);
+
+    NodeList<Node> children = div.getChildNodes();
+    assertEquals(3, children.getLength());
+    assertEquals(txt0, children.getItem(0));
+    assertEquals(btn0, children.getItem(1));
+    assertEquals(txt1, children.getItem(2));
+
+    assertEquals(3, div.getChildCount());
+    assertEquals(txt0, div.getChild(0));
+    assertEquals(btn0, div.getChild(1));
+    assertEquals(txt1, div.getChild(2));
+
+    assertFalse(txt0.hasChildNodes());
+    assertTrue(div.hasChildNodes());
+  }
+
+  /**
+   * getParentElement.
+   */
+  public void testGetParentDoesntCycle() {
+    Element element = Document.get().getBody();
+    int i = 0;
+    while (i < 10 && element != null) {
+      element = element.getParentElement();
+      i++;
+    }
+
+    // If we got here we looped "forever" or passed, as no exception was thrown.
+    if (i == 10) {
+      fail("Cyclic parent structure detected.");
+    }
+
+    // If we get here, we pass, because we encountered no errors going to the
+    // top of the parent hierarchy.
+  }
+
+  /**
+   * isOrHasChild.
+   */
+  public void testIsOrHasChild() {
+    Document doc = Document.get();
+    DivElement div = doc.createDivElement();
+    DivElement childDiv = doc.createDivElement();
+    Text text = doc.createTextNode("foo");
+
+    assertFalse(div.isOrHasChild(childDiv));
+    assertFalse(div.isOrHasChild(text));
+    assertFalse(childDiv.isOrHasChild(text));
+
+    assertTrue(div.isOrHasChild(div));
+    assertTrue(text.isOrHasChild(text));
+
+    div.appendChild(childDiv);
+    childDiv.appendChild(text);
+    assertTrue(div.isOrHasChild(childDiv));
+    assertTrue(div.isOrHasChild(text));
+
+    assertFalse(childDiv.isOrHasChild(div));
+    assertFalse(text.isOrHasChild(childDiv));
+    assertFalse(text.isOrHasChild(div));
+
+    BodyElement body = doc.getBody();
+    body.appendChild(div);
+    assertTrue(body.isOrHasChild(body));
+    assertTrue(body.isOrHasChild(div));
+    assertTrue(body.isOrHasChild(childDiv));
+    assertTrue(body.isOrHasChild(text));
+
+    assertTrue(div.isOrHasChild(div));
+    assertTrue(div.isOrHasChild(childDiv));
+    assertTrue(div.isOrHasChild(text));
+
+    assertFalse(childDiv.isOrHasChild(div));
+    assertFalse(text.isOrHasChild(div));
   }
 
   /**
@@ -56,14 +205,63 @@
   }
 
   /**
-   * setAttribute, getAttribute, hasAttributes, hasAttribute
+   * hasParentElement, getParentElement.
    */
-  public void testAttributes() {
+  public void testNodeParentElement() {
+    Document doc = Document.get();
+    BodyElement body = doc.getBody();
+    DivElement div = doc.createDivElement();
+    Text text = doc.createTextNode("foo");
+
+    // An unattached node should have no parent element.
+    assertFalse(text.hasParentElement());
+    assertFalse(div.hasParentElement());
+    assertNull(text.getParentElement());
+    assertNull(div.getParentElement());
+
+    // Test attached cases.
+    body.appendChild(div);
+    div.appendChild(text);
+    assertTrue(div.hasParentElement());
+    assertTrue(text.hasParentElement());
+    assertEquals(body, div.getParentElement());
+    assertEquals(div, text.getParentElement());
+  }
+
+  /**
+   * nodeType
+   */
+  public void testNodeType() {
     Document doc = Document.get();
     DivElement div = doc.createDivElement();
+    Text txt0 = doc.createTextNode("foo");
 
-    div.setAttribute("id", "myId");
-    assertEquals("myId", div.getAttribute("id"));
+    assertEquals(Node.DOCUMENT_NODE, doc.getNodeType());
+    assertEquals(Node.ELEMENT_NODE, div.getNodeType());
+    assertEquals(Node.TEXT_NODE, txt0.getNodeType());
+  }
+
+  /**
+   * ownerDocument
+   */
+  public void testOwnerDocument() {
+    Document doc = Document.get();
+    BodyElement body = doc.getBody();
+
+    // <div>foo<button/>bar</div>
+    DivElement div = doc.createDivElement();
+    Text txt0 = doc.createTextNode("foo");
+    ButtonElement btn0 = doc.createButtonElement();
+    Text txt1 = doc.createTextNode("bar");
+
+    body.appendChild(div);
+    div.appendChild(txt0);
+    div.appendChild(btn0);
+    div.appendChild(txt1);
+
+    // ownerDocument
+    assertEquals(doc, div.getOwnerDocument());
+    assertEquals(doc, txt0.getOwnerDocument());
   }
 
   /**
@@ -93,96 +291,4 @@
     assertEquals(null, txt0.getPreviousSibling());
     assertEquals(null, txt1.getNextSibling());
   }
-
-  /**
-   * ownerDocument
-   */
-  public void testOwnerDocument() {
-    Document doc = Document.get();
-    BodyElement body = doc.getBody();
-
-    // <div>foo<button/>bar</div>
-    DivElement div = doc.createDivElement();
-    Text txt0 = doc.createTextNode("foo");
-    ButtonElement btn0 = doc.createButtonElement();
-    Text txt1 = doc.createTextNode("bar");
-
-    body.appendChild(div);
-    div.appendChild(txt0);
-    div.appendChild(btn0);
-    div.appendChild(txt1);
-
-    // ownerDocument
-    assertEquals(doc, div.getOwnerDocument());
-    assertEquals(doc, txt0.getOwnerDocument());
-  }
-
-  /**
-   * childNodes, hasChildNodes
-   */
-  public void testChildNodeList() {
-    Document doc = Document.get();
-    BodyElement body = doc.getBody();
-
-    // <div>foo<button/>bar</div>
-    DivElement div = doc.createDivElement();
-    Text txt0 = doc.createTextNode("foo");
-    ButtonElement btn0 = doc.createButtonElement();
-    Text txt1 = doc.createTextNode("bar");
-
-    body.appendChild(div);
-    div.appendChild(txt0);
-    div.appendChild(btn0);
-    div.appendChild(txt1);
-
-    NodeList<Node> children = div.getChildNodes();
-    assertEquals(3, children.getLength());
-    assertEquals(txt0, children.getItem(0));
-    assertEquals(btn0, children.getItem(1));
-    assertEquals(txt1, children.getItem(2));
-
-    assertFalse(txt0.hasChildNodes());
-    assertTrue(div.hasChildNodes());
-  }
-
-  /**
-   * appendChild, insertBefore, removeChild, replaceChild
-   */
-  public void testAppendRemoveReplace() {
-    Document doc = Document.get();
-    BodyElement body = doc.getBody();
-
-    // <div>foo<button/>bar</div>
-    DivElement div = doc.createDivElement();
-    Text txt0 = doc.createTextNode("foo");
-    ButtonElement btn0 = doc.createButtonElement();
-    Text txt1 = doc.createTextNode("bar");
-
-    body.appendChild(div);
-    div.appendChild(txt0);
-    div.appendChild(btn0);
-    div.appendChild(txt1);
-
-    // appendChild, insertBefore
-    ButtonElement btn1 = doc.createButtonElement();
-
-    // <div>foo<button/>bar<button/></div>
-    div.appendChild(btn1);
-    assertEquals(btn1, div.getLastChild());
-
-    // <div>foo<button/><button/>bar</div>
-    div.insertBefore(btn1, txt1);
-    assertEquals(4, div.getChildNodes().getLength());
-    assertEquals(btn1, div.getChildNodes().getItem(2));
-
-    // removeChild
-    // <div>foo<button/>bar</div> (back to original)
-    div.removeChild(btn1);
-    assertEquals(3, div.getChildNodes().getLength());
-
-    // replaceChild
-    div.replaceChild(btn1, btn0);
-    assertEquals(btn1, txt0.getNextSibling());
-    assertEquals(btn1, txt1.getPreviousSibling());
-  }
 }
diff --git a/user/test/com/google/gwt/dom/client/StyleTest.java b/user/test/com/google/gwt/dom/client/StyleTest.java
new file mode 100644
index 0000000..eff4259
--- /dev/null
+++ b/user/test/com/google/gwt/dom/client/StyleTest.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2008 Google Inc.
+ * 
+ * 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.
+ */
+package com.google.gwt.dom.client;
+
+import static com.google.gwt.dom.client.Style.Unit.CM;
+import static com.google.gwt.dom.client.Style.Unit.EM;
+import static com.google.gwt.dom.client.Style.Unit.EX;
+import static com.google.gwt.dom.client.Style.Unit.IN;
+import static com.google.gwt.dom.client.Style.Unit.MM;
+import static com.google.gwt.dom.client.Style.Unit.PC;
+import static com.google.gwt.dom.client.Style.Unit.PCT;
+import static com.google.gwt.dom.client.Style.Unit.PT;
+import static com.google.gwt.dom.client.Style.Unit.PX;
+
+import com.google.gwt.dom.client.Style.Cursor;
+import com.google.gwt.dom.client.Style.Display;
+import com.google.gwt.dom.client.Style.FontStyle;
+import com.google.gwt.dom.client.Style.FontWeight;
+import com.google.gwt.dom.client.Style.HasCssName;
+import com.google.gwt.dom.client.Style.ListStyleType;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.Style.TextDecoration;
+import com.google.gwt.dom.client.Style.VerticalAlign;
+import com.google.gwt.dom.client.Style.Visibility;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests the native {@link Style} class.
+ */
+public class StyleTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.dom.DOMTest";
+  }
+
+  public void testCursor() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setCursor(Cursor.DEFAULT);
+    assertEquals(Cursor.DEFAULT, style.getCursor());
+    style.setCursor(Cursor.AUTO);
+    assertEquals(Cursor.AUTO, style.getCursor());
+    style.setCursor(Cursor.CROSSHAIR);
+    assertEquals(Cursor.CROSSHAIR, style.getCursor());
+    style.setCursor(Cursor.POINTER);
+    assertEquals(Cursor.POINTER, style.getCursor());
+    style.setCursor(Cursor.MOVE);
+    assertEquals(Cursor.MOVE, style.getCursor());
+    style.setCursor(Cursor.E_RESIZE);
+    assertEquals(Cursor.E_RESIZE, style.getCursor());
+    style.setCursor(Cursor.NE_RESIZE);
+    assertEquals(Cursor.NE_RESIZE, style.getCursor());
+    style.setCursor(Cursor.NW_RESIZE);
+    assertEquals(Cursor.NW_RESIZE, style.getCursor());
+    style.setCursor(Cursor.N_RESIZE);
+    assertEquals(Cursor.N_RESIZE, style.getCursor());
+    style.setCursor(Cursor.SE_RESIZE);
+    assertEquals(Cursor.SE_RESIZE, style.getCursor());
+    style.setCursor(Cursor.SW_RESIZE);
+    assertEquals(Cursor.SW_RESIZE, style.getCursor());
+    style.setCursor(Cursor.S_RESIZE);
+    assertEquals(Cursor.S_RESIZE, style.getCursor());
+    style.setCursor(Cursor.W_RESIZE);
+    assertEquals(Cursor.W_RESIZE, style.getCursor());
+    style.setCursor(Cursor.TEXT);
+    assertEquals(Cursor.TEXT, style.getCursor());
+    style.setCursor(Cursor.WAIT);
+    assertEquals(Cursor.WAIT, style.getCursor());
+    style.setCursor(Cursor.HELP);
+    assertEquals(Cursor.HELP, style.getCursor());
+    style.setCursor(Cursor.COL_RESIZE);
+    assertEquals(Cursor.COL_RESIZE, style.getCursor());
+    style.setCursor(Cursor.ROW_RESIZE);
+    assertEquals(Cursor.ROW_RESIZE, style.getCursor());
+  }
+
+  public void testDisplay() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setDisplay(Display.NONE);
+    assertEquals(Display.NONE, style.getDisplay());
+    style.setDisplay(Display.BLOCK);
+    assertEquals(Display.BLOCK, style.getDisplay());
+    style.setDisplay(Display.INLINE);
+    assertEquals(Display.INLINE, style.getDisplay());
+    style.setDisplay(Display.INLINE_BLOCK);
+    assertEquals(Display.INLINE_BLOCK, style.getDisplay());
+  }
+
+  public void testFontStyle() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setFontStyle(FontStyle.NORMAL);
+    assertEquals(FontStyle.NORMAL, style.getFontStyle());
+    style.setFontStyle(FontStyle.ITALIC);
+    assertEquals(FontStyle.ITALIC, style.getFontStyle());
+    style.setFontStyle(FontStyle.OBLIQUE);
+    assertEquals(FontStyle.OBLIQUE, style.getFontStyle());
+  }
+
+  public void testFontWeight() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setFontWeight(FontWeight.NORMAL);
+    assertEquals(FontWeight.NORMAL, style.getFontWeight());
+    style.setFontWeight(FontWeight.BOLD);
+    assertEquals(FontWeight.BOLD, style.getFontWeight());
+    style.setFontWeight(FontWeight.BOLDER);
+    assertEquals(FontWeight.BOLDER, style.getFontWeight());
+    style.setFontWeight(FontWeight.LIGHTER);
+    assertEquals(FontWeight.LIGHTER, style.getFontWeight());
+  }
+
+  public void testListStyleType() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setListStyleType(ListStyleType.NONE);
+    assertEquals(ListStyleType.NONE, style.getListStyleType());
+    style.setListStyleType(ListStyleType.DISC);
+    assertEquals(ListStyleType.DISC, style.getListStyleType());
+    style.setListStyleType(ListStyleType.CIRCLE);
+    assertEquals(ListStyleType.CIRCLE, style.getListStyleType());
+    style.setListStyleType(ListStyleType.SQUARE);
+    assertEquals(ListStyleType.SQUARE, style.getListStyleType());
+    style.setListStyleType(ListStyleType.DECIMAL);
+    assertEquals(ListStyleType.DECIMAL, style.getListStyleType());
+    style.setListStyleType(ListStyleType.LOWER_ALPHA);
+    assertEquals(ListStyleType.LOWER_ALPHA, style.getListStyleType());
+    style.setListStyleType(ListStyleType.UPPER_ALPHA);
+    assertEquals(ListStyleType.UPPER_ALPHA, style.getListStyleType());
+    style.setListStyleType(ListStyleType.LOWER_ROMAN);
+    assertEquals(ListStyleType.LOWER_ROMAN, style.getListStyleType());
+    style.setListStyleType(ListStyleType.UPPER_ROMAN);
+    assertEquals(ListStyleType.UPPER_ROMAN, style.getListStyleType());
+  }
+
+  public void testOverflow() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setOverflow(Overflow.VISIBLE);
+    assertEquals(Overflow.VISIBLE, style.getOverflow());
+    style.setOverflow(Overflow.HIDDEN);
+    assertEquals(Overflow.HIDDEN, style.getOverflow());
+    style.setOverflow(Overflow.SCROLL);
+    assertEquals(Overflow.SCROLL, style.getOverflow());
+    style.setOverflow(Overflow.AUTO);
+    assertEquals(Overflow.AUTO, style.getOverflow());
+  }
+
+  public void testPosition() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setPosition(Position.STATIC);
+    assertEquals(Position.STATIC, style.getPosition());
+    style.setPosition(Position.RELATIVE);
+    assertEquals(Position.RELATIVE, style.getPosition());
+    style.setPosition(Position.ABSOLUTE);
+    assertEquals(Position.ABSOLUTE, style.getPosition());
+    style.setPosition(Position.FIXED);
+    assertEquals(Position.FIXED, style.getPosition());
+  }
+
+  public void testTextDecoration() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setTextDecoration(TextDecoration.NONE);
+    assertEquals(TextDecoration.NONE, style.getTextDecoration());
+    style.setTextDecoration(TextDecoration.UNDERLINE);
+    assertEquals(TextDecoration.UNDERLINE, style.getTextDecoration());
+    style.setTextDecoration(TextDecoration.OVERLINE);
+    assertEquals(TextDecoration.OVERLINE, style.getTextDecoration());
+    style.setTextDecoration(TextDecoration.LINE_THROUGH);
+    assertEquals(TextDecoration.LINE_THROUGH, style.getTextDecoration());
+  }
+
+  public void testVerticalAlign() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setVerticalAlign(VerticalAlign.BASELINE);
+    assertEquals(VerticalAlign.BASELINE, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.SUB);
+    assertEquals(VerticalAlign.SUB, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.SUPER);
+    assertEquals(VerticalAlign.SUPER, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.TOP);
+    assertEquals(VerticalAlign.TOP, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.TEXT_TOP);
+    assertEquals(VerticalAlign.TEXT_TOP, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.MIDDLE);
+    assertEquals(VerticalAlign.MIDDLE, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.BOTTOM);
+    assertEquals(VerticalAlign.BOTTOM, style.getVerticalAlign());
+    style.setVerticalAlign(VerticalAlign.TEXT_BOTTOM);
+    assertEquals(VerticalAlign.TEXT_BOTTOM, style.getVerticalAlign());
+  }
+
+  public void testVisibility() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setVisibility(Visibility.VISIBLE);
+    assertEquals(Visibility.VISIBLE, style.getVisibility());
+    style.setVisibility(Visibility.HIDDEN);
+    assertEquals(Visibility.HIDDEN, style.getVisibility());
+  }
+
+  public void testUnits() {
+    DivElement div = Document.get().createDivElement();
+    Style style = div.getStyle();
+
+    style.setWidth(1, PX);
+    assertEquals("1px", style.getWidth());
+    style.setWidth(1, PCT);
+    assertEquals("1%", style.getWidth());
+    style.setWidth(1, EM);
+    assertEquals("1em", style.getWidth());
+    style.setWidth(1, EX);
+    assertEquals("1ex", style.getWidth());
+    style.setWidth(1, PT);
+    assertEquals("1pt", style.getWidth());
+    style.setWidth(1, PC);
+    assertEquals("1pc", style.getWidth());
+    style.setWidth(1, CM);
+    assertEquals("1cm", style.getWidth());
+    style.setWidth(1, IN);
+    assertEquals("1in", style.getWidth());
+    style.setWidth(1, MM);
+    assertEquals("1mm", style.getWidth());
+  }
+
+  private void assertEquals(HasCssName enumValue, String cssValue) {
+    assertEquals(enumValue.getCssName(), cssValue);
+  }
+}
diff --git a/user/test/com/google/gwt/dom/client/TextTest.java b/user/test/com/google/gwt/dom/client/TextTest.java
new file mode 100644
index 0000000..6e55c40
--- /dev/null
+++ b/user/test/com/google/gwt/dom/client/TextTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009 Google Inc.
+ * 
+ * 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.
+ */
+package com.google.gwt.dom.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Text node tests.
+ */
+public class TextTest extends GWTTestCase {
+
+  private static final String FOLDIN_LEFT = "fold";
+  private static final String FOLDIN_RIGHT = "in";
+  private static final String FOLDIN_BIG = "fold mad magazine in";
+  private static final String FOLDIN_SMALL = "foldin";
+  private static final String FOLDIN_HYPHENATED = "fold-in";
+  private static final String FOLDIN_MIDDLE = " mad magazine ";
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.dom.DOMTest";
+  }
+
+  /**
+   * Test that getting and setting data works.
+   */
+  public void testDataRoundTrip() {
+    Text text = Document.get().createTextNode("initial");
+    assertEquals("initial", text.getData());
+
+    text.setData("replaced");
+    assertEquals("replaced", text.getData());
+  }
+
+  /**
+   * Test {@link Text#getLength()}.
+   */
+  public void testLength() {
+    Text text = Document.get().createTextNode("initial");
+    assertEquals("initial".length(), text.getLength());
+  }
+
+  /**
+   * Test that deleting, inserting, and replacing data works.
+   */
+  public void testInsertAndDeleteData() {
+    Text text = Document.get().createTextNode(FOLDIN_BIG);
+
+    text.deleteData(FOLDIN_LEFT.length(), FOLDIN_MIDDLE.length());
+    assertEquals(FOLDIN_SMALL, text.getData());
+
+    text.insertData(FOLDIN_LEFT.length(), FOLDIN_MIDDLE);
+    assertEquals(FOLDIN_BIG, text.getData());
+
+    text.replaceData(FOLDIN_LEFT.length(), FOLDIN_MIDDLE.length(), "-");
+    assertEquals(FOLDIN_HYPHENATED, text.getData());
+  }
+
+  /**
+   * Test {@link Text#splitText(int)}.
+   */
+  public void testSplitText() {
+    Document doc = Document.get();
+    DivElement div = doc.createDivElement();
+    Text leftNode = doc.createTextNode(FOLDIN_SMALL);
+    div.appendChild(leftNode);
+
+    Text rightNode = leftNode.splitText(FOLDIN_LEFT.length());
+    assertEquals(FOLDIN_LEFT, leftNode.getData());
+    assertEquals(FOLDIN_RIGHT, rightNode.getData());
+    assertEquals(div, leftNode.getParentNode());
+    assertEquals(div, rightNode.getParentNode());
+    assertEquals(leftNode, div.getFirstChild());
+    assertEquals(rightNode, leftNode.getNextSibling());
+  }
+}