Add SafeHtml support to UI widgets (2)

This is a first-pass at adding SafeHtml support to a subset of the widgets. In cases where the class implements HasHTML, HasSafeHtml has been implemented as well. In constructors that accept a string that can be parsed as Html, a SafeHtml constructor has been added. In cases where a method accepts a string that can be parsed as Html, a corresponding SafeHtml method has been added.

Review at http://gwt-code-reviews.appspot.com/847801


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8746 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/tools/api-checker/config/gwt20_21userApi.conf b/tools/api-checker/config/gwt20_21userApi.conf
index 6ff8f42..5e57cf1 100644
--- a/tools/api-checker/config/gwt20_21userApi.conf
+++ b/tools/api-checker/config/gwt20_21userApi.conf
@@ -110,6 +110,35 @@
 # Removing HTTPRequest.
 com.google.gwt.user.client.HTTPRequest MISSING
 
+# SafeHtml adds a safe alternative to the raw html/string methods in widgets.
+# This requires very similar method signatures: For every method(String html), 
+# there needs to be: method(SafeHtml html), etc.
+# Null is not acceptable to any of these methods, so adding the overload is
+# unlikely to break any code besides possibly test mocks.
+com.google.gwt.user.client.ui.Anchor::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.ButtonBase::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.CaptionPanel::CaptionPanel(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.CaptionPanel::setCaptionHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.CheckBox::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.CustomButton::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.DialogBox::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.HTML::HTML(Ljava/lang/String;Z) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.HTML::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.HTMLPanel::HTMLPanel(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.HTMLTable::setHTML(IILjava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.Hyperlink::Hyperlink(Ljava/lang/String;Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.Hyperlink::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.InlineHyperlink::InlineHyperlink(Ljava/lang/String;Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.MenuItem::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.RadioButton::RadioButton(Ljava/lang/String;Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.ResetButton::ResetButton(Ljava/lang/String;Lcom/google/gwt/event/dom/client/ClickHandler;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.RichTextArea::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.StackPanel::setStackText(ILjava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.SubmitButton::SubmitButton(Ljava/lang/String;Lcom/google/gwt/event/dom/client/ClickHandler;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.TabBar::setTabHTML(ILjava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.TabLayoutPanel::setTabHTML(ILjava/lang/String;) OVERLOADED_METHOD_CALL
+com.google.gwt.user.client.ui.TreeItem::setHTML(Ljava/lang/String;) OVERLOADED_METHOD_CALL
+
 # Change signature for native long from double[2] to LongEmul{l=int,m=int,h=int}
 com.google.gwt.lang.LongLib::RUN_IN_JVM MISSING
 com.google.gwt.lang.LongLib::add([D[D) MISSING
diff --git a/user/src/com/google/gwt/safehtml/client/HasSafeHtml.java b/user/src/com/google/gwt/safehtml/client/HasSafeHtml.java
index f9854d5..86da404 100644
--- a/user/src/com/google/gwt/safehtml/client/HasSafeHtml.java
+++ b/user/src/com/google/gwt/safehtml/client/HasSafeHtml.java
@@ -39,5 +39,5 @@
    *
    * @param html the object's new HTML, represented as a {@link SafeHtml} object
    */
-  void setSafeHtml(SafeHtml html);
+  void setHTML(SafeHtml html);
 }
diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index 6d0c941..0e83f8a 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -48,6 +48,7 @@
    <inherits name="com.google.gwt.user.FileUpload"/>
    <inherits name="com.google.gwt.user.datepicker.DatePicker"/>
    <inherits name="com.google.gwt.user.cellview.CellView"/>
+   <inherits name="com.google.gwt.safehtml.SafeHtml" />
 
    <super-source path="translatable"/>
    <source path="client"/>
diff --git a/user/src/com/google/gwt/user/client/ui/Anchor.java b/user/src/com/google/gwt/user/client/ui/Anchor.java
index 89a6278..bda6fce 100644
--- a/user/src/com/google/gwt/user/client/ui/Anchor.java
+++ b/user/src/com/google/gwt/user/client/ui/Anchor.java
@@ -20,6 +20,8 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.i18n.client.BidiUtils;
 import com.google.gwt.i18n.client.HasDirection;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A widget that represents a simple &lt;a&gt; element.
@@ -37,7 +39,7 @@
  * @see Hyperlink
  */
 public class Anchor extends FocusWidget implements HasHorizontalAlignment,
-    HasName, HasHTML, HasWordWrap, HasDirection {
+    HasName, HasHTML, HasWordWrap, HasDirection, HasSafeHtml {
 
   /**
    * Creates an Anchor widget that wraps an existing &lt;a&gt; element.
@@ -85,10 +87,19 @@
 
   /**
    * Creates an anchor for scripting.
-   * 
-   * The anchor's href is set to <code>javascript:;</code>, based on the
+   *
+   * @param html the anchor's text
+   */
+  public Anchor(SafeHtml html) {
+    this(html.asString(), true);
+  }
+
+  /**
+   * Creates an anchor for scripting.
+   *
+   * The anchor's href is set to <code>javascript : ;</code>, based on the
    * expectation that listeners will be added to the anchor.
-   * 
+   *
    * @param text the anchor's text
    * @param asHtml <code>true</code> to treat the specified text as html
    */
@@ -98,7 +109,17 @@
 
   /**
    * Creates an anchor with its text and href (target URL) specified.
-   * 
+   *
+   * @param html the anchor's html
+   * @param href the url to which it will link
+   */
+  public Anchor(SafeHtml html, String href) {
+    this(html.asString(), true, href);
+  }
+
+  /**
+   * Creates an anchor with its text and href (target URL) specified.
+   *
    * @param text the anchor's text
    * @param asHTML <code>true</code> to treat the specified text as html
    * @param href the url to which it will link
@@ -115,12 +136,25 @@
 
   /**
    * Creates a source anchor (link to URI).
-   * 
+   *
    * That is, an anchor with an href attribute specifying the destination URI.
-   * 
+   *
+   * @param html the anchor's html
+   * @param href the url to which it will link
+   * @param target the target frame (e.g. "_blank" to open the link in a new
+   *          window)
+   */
+  public Anchor(SafeHtml html, String href, String target) {
+    this(html.asString(), true, href, target);
+  }
+
+  /**
+   * Creates a source anchor (link to URI).
+   *
+   * That is, an anchor with an href attribute specifying the destination URI.
+   *
    * @param text the anchor's text
-   * @param asHtml asHTML <code>true</code> to treat the specified text as
-   *          html
+   * @param asHtml asHTML <code>true</code> to treat the specified text as html
    * @param href the url to which it will link
    * @param target the target frame (e.g. "_blank" to open the link in a new
    *          window)
@@ -245,6 +279,10 @@
     getAnchorElement().setHref(href);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   public void setHTML(String html) {
     getElement().setInnerHTML(html);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/Button.java b/user/src/com/google/gwt/user/client/ui/Button.java
index 0ac6320..649d821 100644
--- a/user/src/com/google/gwt/user/client/ui/Button.java
+++ b/user/src/com/google/gwt/user/client/ui/Button.java
@@ -19,6 +19,7 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A standard push-button widget.
@@ -72,7 +73,16 @@
 
   /**
    * Creates a button with the given HTML caption.
-   * 
+   *
+   * @param html the HTML caption
+   */
+  public Button(SafeHtml html) {
+    this(html.asString());
+  }
+
+  /**
+   * Creates a button with the given HTML caption.
+   *
    * @param html the HTML caption
    */
   public Button(String html) {
@@ -95,7 +105,17 @@
 
   /**
    * Creates a button with the given HTML caption and click listener.
-   * 
+   *
+   * @param html the html caption
+   * @param handler the click handler
+   */
+  public Button(SafeHtml html, ClickHandler handler) {
+    this(html.asString(), handler);
+  }
+
+  /**
+   * Creates a button with the given HTML caption and click listener.
+   *
    * @param html the HTML caption
    * @param handler the click handler
    */
diff --git a/user/src/com/google/gwt/user/client/ui/ButtonBase.java b/user/src/com/google/gwt/user/client/ui/ButtonBase.java
index 1e6d99d..3714c48 100644
--- a/user/src/com/google/gwt/user/client/ui/ButtonBase.java
+++ b/user/src/com/google/gwt/user/client/ui/ButtonBase.java
@@ -16,13 +16,16 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * Abstract base class for {@link com.google.gwt.user.client.ui.Button},
  * {@link com.google.gwt.user.client.ui.CheckBox},
  * {@link com.google.gwt.user.client.ui.RadioButton}.
  */
-public abstract class ButtonBase extends FocusWidget implements HasHTML {
+public abstract class ButtonBase extends FocusWidget 
+    implements HasHTML, HasSafeHtml {
 
   /**
    * Creates a new ButtonBase that wraps the given browser element.
@@ -45,6 +48,10 @@
     getElement().setInnerHTML(html);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   public void setText(String text) {
     getElement().setInnerText(text);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/CaptionPanel.java b/user/src/com/google/gwt/user/client/ui/CaptionPanel.java
index 4364b2b..e2b4f92 100644
--- a/user/src/com/google/gwt/user/client/ui/CaptionPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/CaptionPanel.java
@@ -20,6 +20,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.FieldSetElement;
 import com.google.gwt.dom.client.LegendElement;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DeferredCommand;
 
@@ -35,7 +36,13 @@
    * Implementation class without browser-specific hacks.
    */
   public static class CaptionPanelImpl {
-    public void setCaption(FieldSetElement fieldset, Element legend, String caption, boolean asHTML) {
+    public void setCaption(
+        FieldSetElement fieldset, Element legend, SafeHtml caption) {
+      setCaption(fieldset, legend, caption.asString(), true);
+    }
+
+    public void setCaption(FieldSetElement fieldset, Element legend,
+        String caption, boolean asHTML) {
       // TODO(bruce): rewrite to be inlinable
       assert (caption != null);
 
@@ -63,8 +70,14 @@
    */
   public static class CaptionPanelImplMozilla extends CaptionPanelImpl {
     @Override
-    public void setCaption(final FieldSetElement fieldset, Element legend, String caption,
-        boolean asHTML) {
+    public void setCaption(
+        final FieldSetElement fieldset, Element legend, SafeHtml caption) {
+      setCaption(fieldset, legend, caption.asString(), true);
+    }
+
+    @Override
+    public void setCaption(final FieldSetElement fieldset, Element legend,
+        String caption, boolean asHTML) {
       fieldset.getStyle().setProperty("display", "none");
       super.setCaption(fieldset, legend, caption, asHTML);
       fieldset.getStyle().setProperty("display", "");
@@ -76,8 +89,14 @@
    */
   public static class CaptionPanelImplSafari extends CaptionPanelImpl {
     @Override
-    public void setCaption(final FieldSetElement fieldset, Element legend, String caption,
-        boolean asHTML) {
+    public void setCaption(
+        final FieldSetElement fieldset, Element legend, SafeHtml caption) {
+      setCaption(fieldset, legend, caption.asString(), true);
+    }
+
+    @Override
+    public void setCaption(final FieldSetElement fieldset, Element legend,
+        String caption, boolean asHTML) {
       fieldset.getStyle().setProperty("visibility", "hidden");
       super.setCaption(fieldset, legend, caption, asHTML);
       DeferredCommand.addCommand(new Command() {
@@ -107,7 +126,16 @@
 
   /**
    * Constructs a CaptionPanel with specified caption text.
-   * 
+   *
+   * @param caption the text of the caption
+   */
+  public CaptionPanel(SafeHtml caption) {
+    this(caption.asString(), true);
+  }
+
+  /**
+   * Constructs a CaptionPanel with specified caption text.
+   *
    * @param captionText the text of the caption, which is automatically escaped
    */
   public CaptionPanel(String captionText) {
@@ -207,10 +235,19 @@
   }
 
   /**
+   * Sets the caption for the panel using a SafeHtml string.
+   *
+   * @param html HTML for the new caption; must not be <code>null</code>
+   */
+  public void setCaptionHTML(SafeHtml html) {
+    setCaptionHTML(html.asString());
+  }
+
+  /**
    * Sets the caption for the panel using text that will be automatically
    * escaped. Pass in empty string to remove the caption completely, leaving
    * just the unadorned panel.
-   * 
+   *
    * @param text text for the new caption; must not be <code>null</code>
    */
   public void setCaptionText(String text) {
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index b6d6aba..21fc4c8 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -23,6 +23,7 @@
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -67,7 +68,16 @@
 
   /**
    * Creates a check box with the specified text label.
-   * 
+   *
+   * @param label the check box's label
+   */
+  public CheckBox(SafeHtml label) {
+    this(label.asString(), true);
+  }
+
+  /**
+   * Creates a check box with the specified text label.
+   *
    * @param label the check box's label
    */
   public CheckBox(String label) {
diff --git a/user/src/com/google/gwt/user/client/ui/CustomButton.java b/user/src/com/google/gwt/user/client/ui/CustomButton.java
index 488233f..f07b08a 100644
--- a/user/src/com/google/gwt/user/client/ui/CustomButton.java
+++ b/user/src/com/google/gwt/user/client/ui/CustomButton.java
@@ -20,6 +20,8 @@
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -137,7 +139,7 @@
    * Represents a button's face. Each face is associated with its own style
    * modifier and, optionally, its own contents html, text, or image.
    */
-  public abstract class Face implements HasHTML {
+  public abstract class Face implements HasHTML, HasSafeHtml {
     private static final String STYLENAME_HTML_FACE = "html-face";
     private final Face delegateTo;
     private Element face;
@@ -174,9 +176,18 @@
 
     /**
      * Set the face's contents as html.
-     * 
+     *
      * @param html html to set as face's contents html
-     * 
+     */
+    public void setHTML(SafeHtml html) {
+      setHTML(html.asString());
+    }
+
+    /**
+     * Set the face's contents as html.
+     *
+     * @param html html to set as face's contents html
+     *
      */
     public void setHTML(String html) {
       face = DOM.createDiv();
@@ -197,7 +208,7 @@
 
     /**
      * Sets the face's contents as text.
-     * 
+     *
      * @param text text to set as face's contents
      */
     public final void setText(String text) {
@@ -746,9 +757,13 @@
     }
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   /**
    * Sets the current face's html.
-   * 
+   *
    * @param html html to set
    */
   @Override
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index c9c2546..acb5056 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -32,6 +32,8 @@
 import com.google.gwt.event.logical.shared.ResizeEvent;
 import com.google.gwt.event.logical.shared.ResizeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -102,7 +104,7 @@
  */
 @SuppressWarnings("deprecation")
 public class DialogBox extends DecoratedPopupPanel implements HasHTML,
-    MouseListener {
+    HasSafeHtml, MouseListener {
   /**
    * Set of characteristic interfaces supported by the {@link DialogBox} caption
    * 
@@ -324,11 +326,23 @@
   }
 
   /**
-   * Sets the text inside the caption.
-   * 
+   * Sets the html string inside the caption.
+   *
    * Use {@link #setWidget(Widget)} to set the contents inside the
    * {@link DialogBox}.
-   * 
+   *
+   * @param html the object's new HTML
+   */
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
+  /**
+   * Sets the text inside the caption.
+   *
+   * Use {@link #setWidget(Widget)} to set the contents inside the
+   * {@link DialogBox}.
+   *
    * @param text the object's new text
    */
   public void setText(String text) {
diff --git a/user/src/com/google/gwt/user/client/ui/HTML.java b/user/src/com/google/gwt/user/client/ui/HTML.java
index ed9495f..65b1b39 100644
--- a/user/src/com/google/gwt/user/client/ui/HTML.java
+++ b/user/src/com/google/gwt/user/client/ui/HTML.java
@@ -17,7 +17,7 @@
 
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
-import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A widget that can contain arbitrary HTML.
@@ -42,7 +42,8 @@
  * {@example com.google.gwt.examples.HTMLExample}
  * </p>
  */
-public class HTML extends Label implements HasDirectionalHtml {
+public class HTML extends Label 
+    implements HasDirectionalHtml, HasDirectionalSafeHtml {
 
   /**
    * Creates an HTML widget that wraps an existing &lt;div&gt; or &lt;span&gt;
@@ -76,6 +77,15 @@
   }
 
   /**
+   * Initializes the widget's HTML from a given {@link SafeHtml} object.
+   *
+   * @param html the new widget's HTML contents
+   */
+  public HTML(SafeHtml html) {
+    this(html.asString());
+  }
+
+  /**
    * Creates an HTML widget with the specified HTML contents.
    *
    * @param html the new widget's HTML contents
@@ -86,6 +96,18 @@
   }
 
   /**
+   * Creates an HTML widget with the specified contents and with the
+   * specified direction.
+   *
+   * @param html the new widget's SafeHtml contents
+   * @param dir the content's direction. Note: {@code Direction.DEFAULT} means
+   *        direction should be inherited from the widget's parent element.
+   */
+  public HTML(SafeHtml html, Direction dir) {
+    this(html.asString(), dir);
+  }
+
+  /**
    * Creates an HTML widget with the specified HTML contents and with the
    * specified direction.
    *
@@ -137,7 +159,6 @@
     setTextOrHtml(html, true);
   }
 
-
   /**
    * Sets the label's content to the given HTML, applying the given direction.
    * See {@link #setText(String, Direction)} for details on potential effects on
@@ -150,4 +171,18 @@
   public void setHTML(String html, Direction dir) {
     setTextOrHtml(html, dir, true);
   }
+
+  /**
+   * Sets this object's contents via known-safe HTML.
+   * 
+   * @see com.google.gwt.safehtml.client.HasSafeHtml#setSafeHtml
+   * @param html the html to set.
+   */
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
+  public void setHTML(SafeHtml html, Direction dir) {
+    setHTML(html.asString(), dir);
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
index 3fd0e6b..e528523 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLPanel.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 import java.util.NoSuchElementException;
 
@@ -56,6 +57,17 @@
     setElement(Document.get().createDivElement());
     getElement().setInnerHTML(html);
   }
+  
+  /**
+   * Initializes the panel's HTML from a given {@link SafeHtml} object.
+   * 
+   * Similar to {@link #HTMLPanel(String)}
+   * 
+   * @param safeHtml the html to set.
+   */
+  public HTMLPanel(SafeHtml safeHtml) {
+    this(safeHtml.asString());
+  }
 
   /**
    * Creates an HTML panel whose root element has the given tag, and with the
diff --git a/user/src/com/google/gwt/user/client/ui/HTMLTable.java b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
index 0c366dd..821b3a8 100644
--- a/user/src/com/google/gwt/user/client/ui/HTMLTable.java
+++ b/user/src/com/google/gwt/user/client/ui/HTMLTable.java
@@ -25,6 +25,7 @@
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -227,7 +228,7 @@
 
     /**
      * Sets the style name associated with the specified cell.
-     * 
+     *
      * @param row the row of the cell whose style name is to be set
      * @param column the column of the cell whose style name is to be set
      * @param styleName the new style name
@@ -1050,8 +1051,20 @@
   }
 
   /**
+   * Sets the HTML contents of the specified cell.
+   *
+   * @param row the cell's row
+   * @param column the cell's column
+   * @param html the cell's safe html contents
+   * @throws IndexOutOfBoundsException
+   */
+  public void setHTML(int row, int column, SafeHtml html) {
+    setHTML(row, column, html.asString());
+  }
+
+  /**
    * Sets the text within the specified cell.
-   * 
+   *
    * @param row the cell's row
    * @param column cell's column
    * @param text the cell's text contents
diff --git a/user/src/com/google/gwt/user/client/ui/HasDirectionalSafeHtml.java b/user/src/com/google/gwt/user/client/ui/HasDirectionalSafeHtml.java
new file mode 100644
index 0000000..add3c1f
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/HasDirectionalSafeHtml.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 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.user.client.ui;
+
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
+
+/**
+ * An object that implements this interface contains html that has a direction.
+ */
+public interface HasDirectionalSafeHtml
+    extends HasDirectionalText, HasSafeHtml {
+  /**
+   * Sets this object's html, also declaring its direction.
+   *
+   * @param html the object's new html
+   * @param dir the html's direction
+   */
+  void setHTML(SafeHtml html, Direction dir);
+}
diff --git a/user/src/com/google/gwt/user/client/ui/Hyperlink.java b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
index 9a322d6..f8c065f 100644
--- a/user/src/com/google/gwt/user/client/ui/Hyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
@@ -23,6 +23,8 @@
 import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -63,7 +65,7 @@
  */
 @SuppressWarnings("deprecation")
 public class Hyperlink extends Widget implements HasHTML, SourcesClickEvents,
-    HasClickHandlers, HasDoubleClickHandlers {
+    HasClickHandlers, HasDoubleClickHandlers, HasSafeHtml {
 
   private static HyperlinkImpl impl = GWT.create(HyperlinkImpl.class);
   
@@ -78,8 +80,19 @@
   }
 
   /**
+   * Creates a hyperlink with its html and target history token specified.
+   *
+   * @param html the hyperlink's safe html
+   * @param targetHistoryToken the history token to which it will link
+   * @see #setTargetHistoryToken
+   */
+  public Hyperlink(SafeHtml html, String targetHistoryToken) {
+    this(html.asString(), true, targetHistoryToken);
+  }
+
+  /**
    * Creates a hyperlink with its text and target history token specified.
-   * 
+   *
    * @param text the hyperlink's text
    * @param asHTML <code>true</code> to treat the specified text as html
    * @param targetHistoryToken the history token to which it will link
@@ -97,11 +110,11 @@
 
   /**
    * Creates a hyperlink with its text and target history token specified.
-   * 
+   *
    * @param text the hyperlink's text
    * @param targetHistoryToken the history token to which it will link, which
-   *     may not be null (use {@link Anchor} instead if you don't need history
-   *     processing)
+   *          may not be null (use {@link Anchor} instead if you don't need
+   *          history processing)
    */
   public Hyperlink(String text, String targetHistoryToken) {
     this();
@@ -185,13 +198,17 @@
     DOM.setInnerHTML(anchorElem, html);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   /**
    * Sets the history token referenced by this hyperlink. This is the history
    * token that will be passed to {@link History#newItem} when this link is
    * clicked.
-   * 
+   *
    * @param targetHistoryToken the new history token, which may not be null (use
-   *        {@link Anchor} instead if you don't need history processing)
+   *          {@link Anchor} instead if you don't need history processing)
    */
   public void setTargetHistoryToken(String targetHistoryToken) {
     assert targetHistoryToken != null
diff --git a/user/src/com/google/gwt/user/client/ui/InlineHTML.java b/user/src/com/google/gwt/user/client/ui/InlineHTML.java
index b5038d7..e624fbe 100644
--- a/user/src/com/google/gwt/user/client/ui/InlineHTML.java
+++ b/user/src/com/google/gwt/user/client/ui/InlineHTML.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A widget that can contain arbitrary HTML.
@@ -71,6 +72,15 @@
   }
 
   /**
+   * Initializes the widget's HTML from a given {@link SafeHtml} object.
+   *
+   * @param html the new widget's HTML contents
+   */
+  public InlineHTML(SafeHtml html) {
+    this(html.asString());
+  }
+
+  /**
    * Creates an HTML widget with the specified HTML contents.
    *
    * @param html the new widget's HTML contents
@@ -81,6 +91,18 @@
   }
 
   /**
+   * Creates an HTML widget with the specified contents and with the
+   * specified direction.
+   *
+   * @param html the new widget's SafeHtml contents
+   * @param dir the content's direction. Note: {@code Direction.DEFAULT} means
+   *        direction should be inherited from the widget's parent element.
+   */
+  public InlineHTML(SafeHtml html, Direction dir) {
+    this(html.asString(), dir);
+  }
+
+  /**
    * Creates an HTML widget with the specified HTML contents and with the
    * specified direction.
    *
diff --git a/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java b/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
index 40a42cb..663d6f9 100644
--- a/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/InlineHyperlink.java
@@ -16,6 +16,8 @@
 
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.safehtml.shared.SafeHtml;
+
 /**
  * A widget that serves as an "internal" hyperlink. That is, it is a link to
  * another state of the running application. It should behave exactly like
@@ -39,8 +41,19 @@
   }
 
   /**
+   * Creates a hyperlink with its html and target history token specified.
+   *
+   * @param html the hyperlink's html
+   * @param targetHistoryToken the history token to which it will link
+   * @see #setTargetHistoryToken
+   */
+  public InlineHyperlink(SafeHtml html, String targetHistoryToken) {
+    this(html.asString(), true, targetHistoryToken);
+  }
+
+  /**
    * Creates a hyperlink with its text and target history token specified.
-   * 
+   *
    * @param text the hyperlink's text
    * @param asHTML <code>true</code> to treat the specified text as html
    * @param targetHistoryToken the history token to which it will link
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index f0de28e..f7d2dc2 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -43,6 +43,7 @@
 import com.google.gwt.i18n.shared.DirectionEstimator;
 import com.google.gwt.i18n.shared.HasDirectionEstimator;
 import com.google.gwt.i18n.shared.WordCountDirectionEstimator;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
@@ -441,6 +442,29 @@
   }
 
   /**
+   * Sets the label's content to the given safe html. See
+   * {@link #setText(String)} for details on potential effects on direction and
+   * alignment.
+   *
+   * @param html the widget's new safe html
+   */
+  protected void setHTML(SafeHtml html) {
+    setTextOrHtml(html.asString(), true);
+  }
+
+  /**
+   * Sets the label's content to the given safe html. See
+   * {@link #setText(String)} for details on potential effects on direction and
+   * alignment.
+   *
+   * @param html the widget's new safe html
+   * @param dir the content's direction
+   */
+  protected void setHTML(SafeHtml html, Direction dir) {
+    setTextOrHtml(html.asString(), dir, true);
+  }
+
+  /**
    * Sets the label's content to the given value (either plain text or HTML).
    * See {@link #setText(String)} for details on potential effects on direction
    * and alignment.
diff --git a/user/src/com/google/gwt/user/client/ui/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index f95d3af..e7cd253 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuBar.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuBar.java
@@ -29,6 +29,7 @@
 import com.google.gwt.resources.client.ClientBundle;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.resources.client.ImageResource.ImageOptions;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
@@ -273,6 +274,18 @@
   }
 
   /**
+   * Adds a menu item to the bar containing SafeHtml, that will fire the given 
+   * command when it is selected.
+   * 
+   * @param html the item's html text
+   * @param cmd the command to be fired
+   * @return the {@link MenuItem} object created
+   */
+  public MenuItem addItem(SafeHtml html, Command cmd) {
+    return addItem(new MenuItem(html, cmd));
+  }
+
+  /**
    * Adds a menu item to the bar, that will fire the given command when it is
    * selected.
    * 
@@ -289,6 +302,18 @@
    * Adds a menu item to the bar, that will open the specified menu when it is
    * selected.
    * 
+   * @param html the item's html text
+   * @param popup the menu to be cascaded from it
+   * @return the {@link MenuItem} object created
+   */
+  public MenuItem addItem(SafeHtml html, MenuBar popup) {
+    return addItem(new MenuItem(html, popup));
+  }
+
+  /**
+   * Adds a menu item to the bar, that will open the specified menu when it is
+   * selected.
+   * 
    * @param text the item's text
    * @param asHTML <code>true</code> to treat the specified text as html
    * @param popup the menu to be cascaded from it
diff --git a/user/src/com/google/gwt/user/client/ui/MenuItem.java b/user/src/com/google/gwt/user/client/ui/MenuItem.java
index 2837861..0e46774 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuItem.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuItem.java
@@ -15,6 +15,8 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 
@@ -27,7 +29,7 @@
  * Each menu item is assigned a unique DOM id in order to support ARIA. See
  * {@link com.google.gwt.user.client.ui.Accessibility} for more information.
  */
-public class MenuItem extends UIObject implements HasHTML {
+public class MenuItem extends UIObject implements HasHTML, HasSafeHtml {
 
   private static final String DEPENDENT_STYLENAME_SELECTED_ITEM = "selected";
 
@@ -37,6 +39,25 @@
   /**
    * Constructs a new menu item that fires a command when it is selected.
    * 
+   * @param html the item's html text
+   */
+  public MenuItem(SafeHtml html) {
+    this(html.asString(), true);
+  }
+
+  /**
+   * Constructs a new menu item that fires a command when it is selected.
+   * 
+   * @param html the item's text
+   * @param cmd the command to be fired when it is selected
+   */
+  public MenuItem(SafeHtml html, Command cmd) {
+    this(html.asString(), true, cmd);
+  }
+
+  /**
+   * Constructs a new menu item that fires a command when it is selected.
+   * 
    * @param text the item's text
    * @param cmd the command to be fired when it is selected
    */
@@ -60,6 +81,16 @@
   /**
    * Constructs a new menu item that cascades to a sub-menu when it is selected.
    * 
+   * @param html the item's text
+   * @param subMenu the sub-menu to be displayed when it is selected
+   */
+  public MenuItem(SafeHtml html, MenuBar subMenu) {
+    this(html.asString(), true, subMenu);
+  }
+
+  /**
+   * Constructs a new menu item that cascades to a sub-menu when it is selected.
+   * 
    * @param text the item's text
    * @param subMenu the sub-menu to be displayed when it is selected
    */
@@ -144,6 +175,10 @@
     DOM.setInnerHTML(getElement(), html);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   /**
    * Sets the sub-menu associated with this item.
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/NamedFrame.java b/user/src/com/google/gwt/user/client/ui/NamedFrame.java
index 402158a..2638ae9 100644
--- a/user/src/com/google/gwt/user/client/ui/NamedFrame.java
+++ b/user/src/com/google/gwt/user/client/ui/NamedFrame.java
@@ -56,6 +56,7 @@
    * @throws IllegalArgumentException if the supplied name is not allowed 
    */
   private static IFrameElement createIFrame(String src, String name) {
+    // TODO(pdr): add SafeHtml support here to prevent XSS
     if (name == null || !isValidName(name.trim())) {
       throw new IllegalArgumentException(
           "expecting one or more non-whitespace chars with no '<', '>', or '&'");
diff --git a/user/src/com/google/gwt/user/client/ui/RadioButton.java b/user/src/com/google/gwt/user/client/ui/RadioButton.java
index 808d1a5..b90641a 100644
--- a/user/src/com/google/gwt/user/client/ui/RadioButton.java
+++ b/user/src/com/google/gwt/user/client/ui/RadioButton.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.EventTarget;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.uibinder.client.UiConstructor;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
@@ -78,6 +79,21 @@
    * using the setName() method will also change their associated group.
    * 
    * @param name the group name with which to associate the radio button
+   * @param label this radio button's html label
+   */
+  public RadioButton(String name, SafeHtml label) {
+    this(name, label.asString(), true);
+  }
+
+  /**
+   * Creates a new radio associated with a particular group, and initialized
+   * with the given HTML label. All radio buttons associated with the same group
+   * name belong to a mutually-exclusive set.
+   * 
+   * Radio buttons are grouped by their name attribute, so changing their name
+   * using the setName() method will also change their associated group.
+   * 
+   * @param name the group name with which to associate the radio button
    * @param label this radio button's label
    */
   public RadioButton(String name, String label) {
diff --git a/user/src/com/google/gwt/user/client/ui/ResetButton.java b/user/src/com/google/gwt/user/client/ui/ResetButton.java
index 83bc66c..cc02323 100644
--- a/user/src/com/google/gwt/user/client/ui/ResetButton.java
+++ b/user/src/com/google/gwt/user/client/ui/ResetButton.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.ButtonElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A standard push-button widget which will automatically reset its enclosing
@@ -63,7 +64,16 @@
 
   /**
    * Creates a button with the given HTML caption.
-   * 
+   *
+   * @param html the HTML caption
+   */
+  public ResetButton(SafeHtml html) {
+    this(html.asString());
+  }
+
+  /**
+   * Creates a button with the given HTML caption.
+   *
    * @param html the HTML caption
    */
   public ResetButton(String html) {
@@ -73,7 +83,17 @@
 
   /**
    * Creates a button with the given HTML caption and click listener.
-   * 
+   *
+   * @param html the HTML caption
+   * @param handler the click handler
+   */
+  public ResetButton(SafeHtml html, ClickHandler handler) {
+    this(html.asString(), handler);
+  }
+
+  /**
+   * Creates a button with the given HTML caption and click listener.
+   *
    * @param html the HTML caption
    * @param handler the click handler
    */
diff --git a/user/src/com/google/gwt/user/client/ui/RichTextArea.java b/user/src/com/google/gwt/user/client/ui/RichTextArea.java
index 8e6f7b4..e174aa2 100644
--- a/user/src/com/google/gwt/user/client/ui/RichTextArea.java
+++ b/user/src/com/google/gwt/user/client/ui/RichTextArea.java
@@ -20,6 +20,8 @@
 import com.google.gwt.event.logical.shared.InitializeEvent;
 import com.google.gwt.event.logical.shared.InitializeHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.ui.impl.RichTextAreaImpl;
 
 /**
@@ -43,7 +45,7 @@
  * </dl>
  */
 public class RichTextArea extends FocusWidget implements HasHTML,
-    HasInitializeHandlers {
+    HasInitializeHandlers, HasSafeHtml {
 
   /**
    * <p>
@@ -656,6 +658,10 @@
     impl.setHTML(html);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+
   public void setText(String text) {
     impl.setText(text);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
index 588d675..035d17a 100644
--- a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
@@ -30,6 +30,7 @@
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -159,6 +160,18 @@
    * stack header.
    * 
    * @param widget the child widget to be added
+   * @param header the html to be shown on its header
+   * @param headerSize the size of the header widget
+   */
+  public void add(final Widget widget, SafeHtml header, double headerSize) {
+    add(widget, header.asString(), true, headerSize);
+  }
+  
+  /**
+   * Adds a child widget to this stack, along with a widget representing the
+   * stack header.
+   * 
+   * @param widget the child widget to be added
    * @param header the text to be shown on its header
    * @param asHtml <code>true</code> to treat the specified text as HTML
    * @param headerSize the size of the header widget
@@ -271,6 +284,20 @@
    * be moved to the requested index.
    * 
    * @param child the widget to be added
+   * @param html the safe html to be shown on its header
+   * @param headerSize the size of the header widget
+   * @param beforeIndex the index before which it will be inserted
+   */
+  public void insert(Widget child, SafeHtml html, double headerSize, 
+      int beforeIndex) {
+    insert(child, html.asString(), true, headerSize, beforeIndex);
+  }
+  
+  /**
+   * Inserts a widget into the panel. If the Widget is already attached, it will
+   * be moved to the requested index.
+   * 
+   * @param child the widget to be added
    * @param text the text to be shown on its header
    * @param asHtml <code>true</code> to treat the specified text as HTML
    * @param headerSize the size of the header widget
@@ -385,6 +412,7 @@
    * 
    * Use care when setting an object's HTML; it is an easy way to expose
    * script-based security problems. Consider using
+   * {@link #setHeaderSafeHtml(int, SafeHtml)} or 
    * {@link #setHeaderText(int, String)} whenever possible.
    * 
    * @param index the index of the header whose HTML is to be set
@@ -400,6 +428,16 @@
   }
 
   /**
+   * Sets a stack header's HTML contents.
+   * 
+   * @param index the index of the header whose HTML is to be set
+   * @param html the header's new HTML contents
+   */
+  public void setHeaderHTML(int index, SafeHtml html) {
+    setHeaderHTML(index, html.asString());
+  }
+  
+  /**
    * Sets a stack header's text contents.
    * 
    * @param index the index of the header whose text is to be set
diff --git a/user/src/com/google/gwt/user/client/ui/StackPanel.java b/user/src/com/google/gwt/user/client/ui/StackPanel.java
index 98cdc37..660817a 100644
--- a/user/src/com/google/gwt/user/client/ui/StackPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/StackPanel.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -88,7 +89,18 @@
   /**
    * Adds a new child with the given widget and header, optionally interpreting
    * the header as HTML.
-   * 
+   *
+   * @param w the widget to be added
+   * @param stackHtml the header html associated with this widget
+   */
+  public void add(Widget w, SafeHtml stackHtml) {
+    add(w, stackHtml.asString(), true);
+  }
+
+  /**
+   * Adds a new child with the given widget and header, optionally interpreting
+   * the header as HTML.
+   *
    * @param w the widget to be added
    * @param stackText the header text associated with this widget
    * @param asHTML <code>true</code> to treat the specified text as HTML
@@ -190,8 +202,18 @@
   }
 
   /**
+   * Sets the html associated with a child by its index.
+   *
+   * @param index the index of the child whose text is to be set
+   * @param html the html to be associated with it
+   */
+  public void setStackText(int index, SafeHtml html) {
+    setStackText(index, html.asString(), true);
+  }
+
+  /**
    * Sets the text associated with a child by its index.
-   * 
+   *
    * @param index the index of the child whose text is to be set
    * @param text the text to be associated with it
    * @param asHTML <code>true</code> to treat the specified text as HTML
diff --git a/user/src/com/google/gwt/user/client/ui/SubmitButton.java b/user/src/com/google/gwt/user/client/ui/SubmitButton.java
index c86f466..07223f4 100644
--- a/user/src/com/google/gwt/user/client/ui/SubmitButton.java
+++ b/user/src/com/google/gwt/user/client/ui/SubmitButton.java
@@ -18,6 +18,7 @@
 import com.google.gwt.dom.client.ButtonElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * A standard push-button widget which will automatically submit its enclosing
@@ -65,7 +66,16 @@
 
   /**
    * Creates a button with the given HTML caption.
-   * 
+   *
+   * @param html the HTML caption
+   */
+  public SubmitButton(SafeHtml html) {
+    this(html.asString());
+  }
+
+  /**
+   * Creates a button with the given HTML caption.
+   *
    * @param html the HTML caption
    */
   public SubmitButton(String html) {
@@ -75,7 +85,17 @@
 
   /**
    * Creates a button with the given HTML caption and click listener.
-   * 
+   *
+   * @param html the HTML caption
+   * @param handler the click handler
+   */
+  public SubmitButton(SafeHtml html, ClickHandler handler) {
+    this(html.asString(), handler);
+  }
+
+  /**
+   * Creates a button with the given HTML caption and click listener.
+   *
    * @param html the HTML caption
    * @param handler the click handler
    */
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index b76bbdb..ebdfaad 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -94,6 +94,8 @@
  * <dd>the suggest box itself</dd>
  * </dl>
  * 
+ * TODO(pdr): Add SafeHtml support to this and implementing classes.
+ * 
  * @see SuggestOracle
  * @see MultiWordSuggestOracle
  * @see TextBoxBase
@@ -152,6 +154,9 @@
     /**
      * Update the list of visible suggestions.
      * 
+     * Use care when using isDisplayStringHtml; it is an easy way to expose 
+     * script-based security problems. 
+     * 
      * @param suggestBox the suggest box where the suggestions originated
      * @param suggestions the suggestions to show
      * @param isDisplayStringHTML should the suggestions be displayed as HTML
diff --git a/user/src/com/google/gwt/user/client/ui/TabBar.java b/user/src/com/google/gwt/user/client/ui/TabBar.java
index 812dc37..97ff54a 100644
--- a/user/src/com/google/gwt/user/client/ui/TabBar.java
+++ b/user/src/com/google/gwt/user/client/ui/TabBar.java
@@ -33,6 +33,7 @@
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 /**
@@ -223,6 +224,15 @@
   /**
    * Adds a new tab with the specified text.
    * 
+   * @param html the new tab's html
+   */
+  public void addTab(SafeHtml html) {
+    addTab(html.asString(), true);
+  }
+  
+  /**
+   * Adds a new tab with the specified text.
+   * 
    * @param text the new tab's text
    */
   public void addTab(String text) {
@@ -322,6 +332,16 @@
   /**
    * Inserts a new tab at the specified index.
    * 
+   * @param html the new tab's html
+   * @param beforeIndex the index before which this tab will be inserted
+   */
+  public void insertTab(SafeHtml html, int beforeIndex) {
+    insertTab(html.asString(), true, beforeIndex);
+  }
+  
+  /**
+   * Inserts a new tab at the specified index.
+   * 
    * @param text the new tab's text
    * @param asHTML <code>true</code> to treat the specified text as HTML
    * @param beforeIndex the index before which this tab will be inserted
@@ -502,7 +522,8 @@
    * 
    * Use care when setting an object's HTML; it is an easy way to expose
    * script-based security problems. Consider using
-   * {@link #setTabText(int, String)} whenever possible.
+   * {@link #setTabText(int, String)} or {@link setTabHTML(int, SafeHtml)}
+   * whenever possible.
    * 
    * @param index the index of the tab whose HTML is to be set
    * @param html the tab new HTML
@@ -516,6 +537,16 @@
   }
 
   /**
+   * Sets a tab's contents via safe html.
+   * 
+   * @param index the index of the tab whose HTML is to be set
+   * @param html the tab new HTML
+   */
+  public void setTabHTML(int index, SafeHtml html) {
+    setTabHTML(index, html.asString());
+  }
+  
+  /**
    * Sets a tab's text contents.
    * 
    * @param index the index of the tab whose text is to be set
diff --git a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
index ad8f43a..daaf0f7 100644
--- a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
@@ -30,6 +30,7 @@
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.layout.client.Layout.Alignment;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -177,7 +178,7 @@
   /**
    * Adds a widget to the panel. If the Widget is already attached, it will be
    * moved to the right-most index.
-   * 
+   *
    * @param child the widget to be added
    * @param text the text to be shown on its tab
    */
@@ -188,7 +189,18 @@
   /**
    * Adds a widget to the panel. If the Widget is already attached, it will be
    * moved to the right-most index.
-   * 
+   *
+   * @param child the widget to be added
+   * @param html the html to be shown on its tab
+   */
+  public void add(Widget child, SafeHtml html) {
+    add(child, html.asString(), true);
+  }
+
+  /**
+   * Adds a widget to the panel. If the Widget is already attached, it will be
+   * moved to the right-most index.
+   *
    * @param child the widget to be added
    * @param text the text to be shown on its tab
    * @param asHtml <code>true</code> to treat the specified text as HTML
@@ -284,7 +296,19 @@
   /**
    * Inserts a widget into the panel. If the Widget is already attached, it will
    * be moved to the requested index.
-   * 
+   *
+   * @param child the widget to be added
+   * @param html the html to be shown on its tab
+   * @param beforeIndex the index before which it will be inserted
+   */
+  public void insert(Widget child, SafeHtml html, int beforeIndex) {
+    insert(child, html.asString(), true, beforeIndex);
+  }
+
+  /**
+   * Inserts a widget into the panel. If the Widget is already attached, it will
+   * be moved to the requested index.
+   *
    * @param child the widget to be added
    * @param text the text to be shown on its tab
    * @param asHtml <code>true</code> to treat the specified text as HTML
@@ -438,6 +462,7 @@
    * 
    * Use care when setting an object's HTML; it is an easy way to expose
    * script-based security problems. Consider using
+   * {@link #setTabSafeHtml(int, SafeHtml)} or 
    * {@link #setTabText(int, String)} whenever possible.
    * 
    * @param index the index of the tab whose HTML is to be set
@@ -449,8 +474,18 @@
   }
 
   /**
+   * Sets a tab's HTML contents.
+   *
+   * @param index the index of the tab whose HTML is to be set
+   * @param html the tab's new HTML contents
+   */
+  public void setTabHTML(int index, SafeHtml html) {
+    setTabHTML(index, html.asString());
+  }
+
+  /**
    * Sets a tab's text contents.
-   * 
+   *
    * @param index the index of the tab whose text is to be set
    * @param text the object's new text
    */
diff --git a/user/src/com/google/gwt/user/client/ui/TreeItem.java b/user/src/com/google/gwt/user/client/ui/TreeItem.java
index c2eacfb..6aed8a5 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeItem.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeItem.java
@@ -19,6 +19,8 @@
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.i18n.client.LocaleInfo;
+import com.google.gwt.safehtml.client.HasSafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtml;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 
@@ -37,7 +39,7 @@
  * {@example com.google.gwt.examples.TreeExample}
  * </p>
  */
-public class TreeItem extends UIObject implements HasHTML {
+public class TreeItem extends UIObject implements HasHTML, HasSafeHtml {
 
   /**
    * The margin applied to child items.
@@ -285,6 +287,15 @@
     this();
     setHTML(html);
   }
+  
+  /**
+   * Constructs a tree item with the given HTML.
+   * 
+   * @param html the item's HTML
+   */
+  public TreeItem(SafeHtml html) {
+    this(html.asString());
+  }
 
   /**
    * Constructs a tree item with the given <code>Widget</code>.
@@ -599,6 +610,10 @@
     DOM.setInnerHTML(contentElem, html);
   }
 
+  public void setHTML(SafeHtml html) {
+    setHTML(html.asString());
+  }
+  
   /**
    * Selects or deselects this item.
    * 
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 69992ec..4c64cee 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -64,6 +64,8 @@
 import com.google.gwt.user.client.ui.HorizontalSplitPanelTest;
 import com.google.gwt.user.client.ui.HyperlinkTest;
 import com.google.gwt.user.client.ui.ImageTest;
+import com.google.gwt.user.client.ui.InlineHTMLTest;
+import com.google.gwt.user.client.ui.InlineHyperlinkTest;
 import com.google.gwt.user.client.ui.LabelTest;
 import com.google.gwt.user.client.ui.LazyPanelTest;
 import com.google.gwt.user.client.ui.LinearPanelTest;
@@ -74,6 +76,7 @@
 import com.google.gwt.user.client.ui.PopupTest;
 import com.google.gwt.user.client.ui.PrefixTreeTest;
 import com.google.gwt.user.client.ui.RadioButtonTest;
+import com.google.gwt.user.client.ui.ResetButtonTest;
 import com.google.gwt.user.client.ui.RichTextAreaTest;
 import com.google.gwt.user.client.ui.RootPanelTest;
 import com.google.gwt.user.client.ui.ScrollPanelTest;
@@ -82,6 +85,7 @@
 import com.google.gwt.user.client.ui.SplitLayoutPanelTest;
 import com.google.gwt.user.client.ui.StackLayoutPanelTest;
 import com.google.gwt.user.client.ui.StackPanelTest;
+import com.google.gwt.user.client.ui.SubmitButtonTest;
 import com.google.gwt.user.client.ui.SuggestBoxTest;
 import com.google.gwt.user.client.ui.TabBarTest;
 import com.google.gwt.user.client.ui.TabLayoutPanelTest;
@@ -118,15 +122,18 @@
     suite.addTestSuite(AnchorTest.class);
     suite.addTestSuite(AsyncProxyTest.class);
     suite.addTestSuite(ButtonTest.class);
+    suite.addTestSuite(CalendarUtilTest.class);
     suite.addTestSuite(CaptionPanelTest.class);
     suite.addTestSuite(CheckBoxTest.class);
+    suite.addTestSuite(ClassInitTest.class);
     suite.addTestSuite(ClippedImagePrototypeTest.class);
     suite.addTestSuite(CommandExecutorTest.class);
     suite.addTestSuite(CompositeTest.class);
     suite.addTestSuite(CookieTest.class);
+    suite.addTestSuite(CreateEventTest.class);
     suite.addTestSuite(CustomButtonTest.class);
-    suite.addTestSuite(CalendarUtilTest.class);
     suite.addTestSuite(DateBoxTest.class);
+    suite.addTestSuite(DateChangeEventTest.class);
     suite.addTestSuite(DatePickerTest.class);
     suite.addTestSuite(DeckPanelTest.class);
     suite.addTestSuite(DecoratedPopupTest.class);
@@ -162,6 +169,8 @@
     suite.addTestSuite(HyperlinkTest.class);
     suite.addTestSuite(ImageBundleGeneratorTest.class);
     suite.addTestSuite(ImageTest.class);
+    suite.addTestSuite(InlineHTMLTest.class);
+    suite.addTestSuite(InlineHyperlinkTest.class);
     suite.addTestSuite(LabelTest.class);
     suite.addTestSuite(LayoutTest.class);
     suite.addTestSuite(LazyPanelTest.class);
@@ -173,13 +182,16 @@
     suite.addTestSuite(PopupTest.class);
     suite.addTestSuite(PrefixTreeTest.class);
     suite.addTestSuite(RadioButtonTest.class);
+    suite.addTestSuite(ResetButtonTest.class);
     suite.addTestSuite(RichTextAreaTest.class);
+    suite.addTestSuite(RootPanelTest.class);
     suite.addTestSuite(ScrollPanelTest.class);
     suite.addTestSuite(SimpleCheckBoxTest.class);
     suite.addTestSuite(SimpleRadioButtonTest.class);
     suite.addTestSuite(SplitLayoutPanelTest.class);
     suite.addTestSuite(StackLayoutPanelTest.class);
     suite.addTestSuite(StackPanelTest.class);
+    suite.addTestSuite(SubmitButtonTest.class);
     suite.addTestSuite(SuggestBoxTest.class);
     suite.addTestSuite(TabBarTest.class);
     suite.addTestSuite(TabLayoutPanelTest.class);
@@ -196,13 +208,9 @@
     suite.addTestSuite(WidgetIteratorsTest.class);
     suite.addTestSuite(WidgetOnLoadTest.class);
     suite.addTestSuite(WidgetSubclassingTest.class);
+    suite.addTestSuite(WidgetTest.class);
     suite.addTestSuite(WindowTest.class);
     suite.addTestSuite(XMLTest.class);
-    suite.addTestSuite(ClassInitTest.class);
-    suite.addTestSuite(DateChangeEventTest.class);
-    suite.addTestSuite(CreateEventTest.class);
-    suite.addTestSuite(WidgetTest.class);
-    suite.addTestSuite(RootPanelTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/AnchorTest.java b/user/test/com/google/gwt/user/client/ui/AnchorTest.java
index 076e5aa..9d5c013 100644
--- a/user/test/com/google/gwt/user/client/ui/AnchorTest.java
+++ b/user/test/com/google/gwt/user/client/ui/AnchorTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.i18n.client.HasDirection;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 
 /**
@@ -44,6 +45,7 @@
     }
   }
 
+  private static final String html = "<b>hello</b><i>world</i>";
   private static final String TEST_URL0 = "http://www.google.com/";
   private static final String TEST_URL1 = "http://code.google.com/";
 
@@ -113,6 +115,28 @@
     }
   }
 
+  public void testSafeHtmlConstructors() {
+    String href = "http://example.com/example.png";
+    String target = "_blank";
+    Anchor anchor1 = new Anchor(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html.toLowerCase(), anchor1.getHTML().toLowerCase());
+    
+    Anchor anchor2 = new Anchor(
+        SafeHtmlUtils.fromSafeConstant(html), href, target);
+    
+    assertEquals(html, anchor2.getHTML().toLowerCase());
+    assertEquals(href, anchor2.getHref());
+    assertEquals(target, anchor2.getTarget());
+  }
+
+  public void testSetSafeHtml() {
+    Anchor anchor = new Anchor("hello");
+    anchor.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, anchor.getHTML().toLowerCase());
+  }
+
   public void testScriptAnchor() {
     Anchor anchor = new Anchor("Foo");
 
diff --git a/user/test/com/google/gwt/user/client/ui/ButtonTest.java b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
index f570f20..a70cd17 100644
--- a/user/test/com/google/gwt/user/client/ui/ButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/ButtonTest.java
@@ -19,6 +19,7 @@
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
 import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
@@ -28,6 +29,8 @@
  */
 public class ButtonTest extends GWTTestCase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
@@ -103,4 +106,24 @@
 
     b.click();
   }
+
+  public void testSetSafeHtml() {
+    Button button = new Button("hello");
+    button.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+
+  public void testSafeHtmlConstructor() {
+    Button button = new Button(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+
+  public void testSafeHtmlWithHandler() {
+    H handler = new H();
+    Button button = new Button(SafeHtmlUtils.fromSafeConstant(html), handler);
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/CaptionPanelTest.java b/user/test/com/google/gwt/user/client/ui/CaptionPanelTest.java
index 7dff6fb..13d195b 100644
--- a/user/test/com/google/gwt/user/client/ui/CaptionPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CaptionPanelTest.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.ui.HasWidgetsTester.WidgetAdder;
 
 /**
@@ -24,6 +25,8 @@
  */
 public class CaptionPanelTest extends GWTTestCase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
@@ -292,4 +295,16 @@
     }
   }
 
+  public void testSafeHtmlConstructor() {
+    CaptionPanel panel = new CaptionPanel(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, panel.getCaptionHTML().toLowerCase());
+  }
+
+  public void testSetCaptionSafeHtml() {
+    CaptionPanel panel = new CaptionPanel("hiworld");
+    panel.setCaptionHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, panel.getCaptionHTML().toLowerCase());
+  }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
index 9550bf1..f44d04a 100644
--- a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
@@ -24,6 +24,7 @@
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.event.shared.HandlerManager;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 
@@ -55,6 +56,8 @@
     }
   }
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   private CheckBox cb;
 
   @Override
@@ -221,6 +224,19 @@
     assertTrue(cb.getValue());
   }
 
+  public void testSafeHtmlConstructor() {
+    CheckBox box = new CheckBox(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, box.getHTML().toLowerCase());
+  }
+
+  public void testSetSafeHtml() {
+    CheckBox box = new CheckBox("hello");
+    box.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, box.getHTML().toLowerCase());
+  }
+
   @SuppressWarnings("deprecation")
   public void testValueChangeEvent() {
     Handler h = new Handler();
diff --git a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
index b2b7fde..75a76cc 100644
--- a/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CustomButtonTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.CustomButton.Face;
@@ -37,6 +38,8 @@
  */
 public class CustomButtonTest extends GWTTestCase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   public String getModuleName() {
     return "com.google.gwt.user.User";
   }
@@ -148,6 +151,13 @@
     }
   }
 
+  public void testSetSafeHtml() {
+    PushButton button = new PushButton();
+    button.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+
   public void testSyntheticClick() {
     PushButton b = new PushButton();
     final ArrayList<String> events = new ArrayList<String>();
diff --git a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
index d6603ae..6937427 100644
--- a/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DialogBoxTest.java
@@ -19,6 +19,7 @@
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.junit.DoNotRunWith;
 import com.google.gwt.junit.Platform;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.DeferredCommand;
@@ -28,6 +29,8 @@
  */
 public class DialogBoxTest extends PopupTest {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.DebugTest";
@@ -141,6 +144,13 @@
     testDependantPopupPanel(primaryPopup);
   }
 
+  public void testSafeHtmlConstructor() {
+    DialogBox box = new DialogBox();
+    box.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+
+    assertEquals(html, box.getHTML().toLowerCase());
+  }
+
   @Override
   protected PopupPanel createPopupPanel() {
     return new DialogBox();
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
index 6e71cb6..026a8a9 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLPanelTest.java
@@ -15,15 +15,17 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.Node;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
 
 /**
  * Tests the HTMLPanel widget.
  */
 public class HTMLPanelTest extends GWTTestCase {
-
   static class Adder implements HasWidgetsTester.WidgetAdder {
     public void addChild(HasWidgets container, Widget child) {
       ((HTMLPanel) container).add(child, "w00t");
@@ -35,6 +37,14 @@
   }
 
   /**
+   * A SafeHtmlTemplates interface for testing.
+   */
+  public interface TestTemplates extends SafeHtmlTemplates {
+    @Template("<table><tr><td>{0} <span id='labelHere'></span></td></tr></table>")
+    SafeHtml tableTemplate(String body);
+  }
+
+  /**
    * Tests {@link HTMLPanel#add(Widget, String)}.
    */
   public void testAddToElementWithId() {
@@ -240,5 +250,33 @@
     assertEquals("Unattached's parent element should be unaffected",
         attachedParentElem, attached.getElement().getParentElement());
   }
-}
 
+  /**
+   * Tests SafeHtml constructor
+   */
+  public void testSafeHtml() {
+    TestTemplates templates = GWT.create(TestTemplates.class);
+    SafeHtml table = templates.tableTemplate("Hello");
+    
+    HTMLPanel hp = new HTMLPanel(table);
+    InlineLabel label = new InlineLabel("World");
+    hp.addAndReplaceElement(label, "labelHere");
+
+    Element parent = label.getElement().getParentElement();
+    assertEquals("td", parent.getTagName().toLowerCase());
+
+    parent = parent.getParentElement();
+    assertEquals("tr", parent.getTagName().toLowerCase());
+
+    // Look for the table in the main panel div
+    Element firstChild = null;
+    while (parent != null && parent != hp.getElement()) {
+      firstChild = parent;
+      parent = parent.getParentElement();
+    }
+
+    assertNotNull(parent);
+    assertEquals("div", parent.getTagName().toLowerCase());
+    assertEquals("table", firstChild.getTagName().toLowerCase());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLTableTestBase.java b/user/test/com/google/gwt/user/client/ui/HTMLTableTestBase.java
index 7a7ba79..17c3d57 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLTableTestBase.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLTableTestBase.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.dom.client.TableCellElement;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.HTMLTable.Cell;
 import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
@@ -31,13 +32,14 @@
  * Base test for HTMLTable derived classes.
  */
 public abstract class HTMLTableTestBase extends GWTTestCase {
-
   static class Adder implements HasWidgetsTester.WidgetAdder {
     public void addChild(HasWidgets container, Widget child) {
       ((HTMLTable) container).setWidget(0, 0, child);
     }
   }
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   public static void assertEquals(Object[] x, Object[] y) {
     assertEquals(x.length, y.length);
     for (int i = 0; i < y.length; i++) {
@@ -237,6 +239,12 @@
     formatter.setWidth(0, 2, "100%");
   }
 
+  public void testSafeHtml() {
+    HTMLTable table = getTable(1, 1);
+    table.setHTML(0, 0, SafeHtmlUtils.fromSafeConstant(html));
+    assertEquals(html, table.getHTML(0, 0).toLowerCase());
+  }
+
   public void testStyles() {
     HTMLTable t = getTable(4, 4);
     t.getCellFormatter().setStyleName(2, 2, "hello");
diff --git a/user/test/com/google/gwt/user/client/ui/HTMLTest.java b/user/test/com/google/gwt/user/client/ui/HTMLTest.java
index 363a261..ee84fc1 100644
--- a/user/test/com/google/gwt/user/client/ui/HTMLTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HTMLTest.java
@@ -19,6 +19,7 @@
 import com.google.gwt.i18n.client.BidiUtils;
 import com.google.gwt.i18n.client.HasDirection.Direction;
 import com.google.gwt.i18n.client.LocaleInfo;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 
 /**
  * Tests {@link HTML}.
@@ -26,6 +27,7 @@
  */
 public class HTMLTest extends LabelTest {
 
+  private static final String html = "<b>hello</b><i>world</i>";
   private final String EN_HTML = "<b style=\"color: red\">" + EN_TEXT + "</b>";
   private final String IW_HTML = "<b style=\"color: red\">" + IW_TEXT + "</b>";
   private HTML label;
@@ -35,6 +37,27 @@
     return "com.google.gwt.user.User";
   }
 
+  // test that the SafeHtml constructor creates the HTML element correctly.
+  public void testSafeHtmlConstructor() {
+    HTML htmlElement = new HTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, htmlElement.getHTML().toLowerCase());
+  }
+
+  // test that the SafeHtml constructor creates the wordwrapped'ed HTML.
+  public void testSafeHtmlConstructorWithDirection() {
+    HTML htmlElementLTR = new HTML(
+        SafeHtmlUtils.fromSafeConstant(html), Direction.LTR);
+    HTML htmlElementRTL = new HTML(
+        SafeHtmlUtils.fromSafeConstant(html), Direction.RTL);
+    
+    assertEquals(html, htmlElementRTL.getHTML().toLowerCase());
+    assertEquals(html, htmlElementLTR.getHTML().toLowerCase());
+    
+    assertEquals(Direction.LTR, htmlElementLTR.getTextDirection());
+    assertEquals(Direction.RTL, htmlElementRTL.getTextDirection());
+  }
+
   // setDirection is deprecated; this only assures backwards compatibility.
   public void testSetDirection() {
     for (int i = 0; i < 2; i++) {
@@ -72,6 +95,22 @@
     testSetDirectionEstimatorAndSetTextOrHtml(false);
   }
 
+  public void testSetSafeHtml() {
+    HTML htmlElement = new HTML("<b>foo</b>");
+    htmlElement.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, htmlElement.getHTML().toLowerCase());
+  }
+
+  @SuppressWarnings("deprecation")
+  public void testSetSafeHtmlWithDirection() {
+    HTML htmlElement = new HTML("<b>foo</b>");
+    htmlElement.setHTML(SafeHtmlUtils.fromSafeConstant(html), Direction.LTR);
+    
+    assertEquals(html, htmlElement.getHTML().toLowerCase());
+    assertEquals(Direction.LTR, htmlElement.getDirection());
+  }
+
   /**
    * Asserts that both the {@link Label#getTextDirection} and the physical dir
    * attribute match the expected direction.
@@ -167,4 +206,3 @@
     }
   }
 }
-
diff --git a/user/test/com/google/gwt/user/client/ui/HyperlinkTest.java b/user/test/com/google/gwt/user/client/ui/HyperlinkTest.java
index 0cff670..f97c6df 100644
--- a/user/test/com/google/gwt/user/client/ui/HyperlinkTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HyperlinkTest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 
 /**
@@ -23,6 +24,8 @@
  */
 public class HyperlinkTest extends GWTTestCase {
 
+  static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.DebugTest";
@@ -34,4 +37,19 @@
     UIObjectTest.assertDebugId("myLink-wrapper", link.getElement());
     UIObjectTest.assertDebugId("myLink", DOM.getFirstChild(link.getElement()));
   }
+
+  public void testSafeHtmlConstructor() {
+    String token = "myToken";
+    Hyperlink link = new Hyperlink(SafeHtmlUtils.fromSafeConstant(html), token);
+    
+    assertEquals(html, link.getHTML().toLowerCase());
+  }
+
+  public void testSetSafeHtml() {
+    String token = "myToken";
+    Hyperlink link = new Hyperlink("foobar", token);
+    link.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, link.getHTML().toLowerCase());
+  }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/InlineHTMLTest.java b/user/test/com/google/gwt/user/client/ui/InlineHTMLTest.java
new file mode 100644
index 0000000..41a1ef6
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/InlineHTMLTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 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.user.client.ui;
+
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+
+/**
+ * Tests {@link InlineHTML}.
+ * Note: tests only the direction and alignment logic.
+ */
+public class InlineHTMLTest extends LabelTest {
+
+  static final String html = "<b>hello</b><i>world</i>";
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  // test that the SafeHtml constructor creates the HTML element correctly.
+  public void testSafeHtmlConstructor() {
+    InlineHTML htmlElement = 
+      new InlineHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, htmlElement.getHTML().toLowerCase());
+  }
+
+  // test that the SafeHtml constructor creates the direction HTML.
+  public void testSafeHtmlConstructorWithDirection() {
+    InlineHTML htmlElementLTR = 
+      new InlineHTML(SafeHtmlUtils.fromSafeConstant(html), Direction.LTR);
+    InlineHTML htmlElementRTL = 
+      new InlineHTML(SafeHtmlUtils.fromSafeConstant(html), Direction.RTL);
+    
+    assertEquals(html, htmlElementRTL.getHTML().toLowerCase());
+    assertEquals(html, htmlElementLTR.getHTML().toLowerCase());
+    assertEquals(Direction.LTR, htmlElementLTR.getTextDirection());
+    assertEquals(Direction.RTL, htmlElementRTL.getTextDirection());
+  }
+
+  public void testSetSafeHtml() {
+    InlineHTML htmlElement = new InlineHTML("<b>foo</b>");
+    htmlElement.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, htmlElement.getHTML().toLowerCase());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/InlineHyperlinkTest.java b/user/test/com/google/gwt/user/client/ui/InlineHyperlinkTest.java
new file mode 100644
index 0000000..88c8937
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/InlineHyperlinkTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 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.user.client.ui;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+
+/**
+ * Tests {@link InlineHyperlinkTest}.
+ */
+public class InlineHyperlinkTest extends GWTTestCase {
+
+  static final String html = "<b>hello</b><i>world</i>";
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.DebugTest";
+  }
+
+  public void testSafeHtmlConstructor() {
+    String token = "myToken";
+    InlineHyperlink link = 
+      new InlineHyperlink(SafeHtmlUtils.fromSafeConstant(html), token);
+    
+    assertEquals(html, link.getHTML().toLowerCase());
+  }
+
+  public void testSetSafeHtml() {
+    String token = "myToken";
+    InlineHyperlink link = new InlineHyperlink("foobar", token);
+    link.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, link.getHTML().toLowerCase());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/LabelTest.java b/user/test/com/google/gwt/user/client/ui/LabelTest.java
index bde9516..00a949d 100644
--- a/user/test/com/google/gwt/user/client/ui/LabelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/LabelTest.java
@@ -22,6 +22,7 @@
 import com.google.gwt.i18n.client.BidiUtils;
 import com.google.gwt.i18n.client.HasDirection.Direction;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.ui.HasHorizontalAlignment.AutoHorizontalAlignmentConstant;
 import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
 
@@ -32,6 +33,9 @@
  */
 public class LabelTest extends GWTTestCase {
 
+  static final String html1 = "<b>hello</b><i>world</i>:)";
+  static final String html2 = "<b>goodbye</b><i>world</i>:(";
+
   protected final String EN_TEXT = "abc";
   protected final String IW_TEXT = "\u05e0\u05e1\u05e2";
   private Label label;
@@ -120,7 +124,20 @@
         HasHorizontalAlignment.ALIGN_LEFT,
         HasAutoHorizontalAlignment.ALIGN_CONTENT_START);
   }
-  
+
+  @SuppressWarnings("deprecation")
+  public void testSetSafeHtml() {
+    Label label = new Label("foo");
+    label.setHTML(SafeHtmlUtils.fromSafeConstant(html1));
+    
+    assertEquals(html1, label.getTextOrHtml(true).toLowerCase());
+    
+    label.setHTML(SafeHtmlUtils.fromSafeConstant(html2), Direction.LTR);
+    
+    assertEquals(html2, label.getTextOrHtml(true).toLowerCase());
+    assertEquals(Direction.LTR, label.getDirection());
+  }
+
   /**
    * Create a div and attach it to the {@link RootPanel}.
    *
diff --git a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
index 632e3ac..b183c6d 100644
--- a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
+++ b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.event.dom.client.KeyCodes;
 import com.google.gwt.junit.DoNotRunWith;
 import com.google.gwt.junit.Platform;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DeferredCommand;
 
@@ -30,6 +31,8 @@
  */
 public class MenuBarTest extends WidgetTestBase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   /**
    * A blank command.
    */
@@ -309,6 +312,24 @@
     }
   }
 
+  public void testSafeHtml() {
+    MenuBar bar = new MenuBar(true);
+    
+    // ensure safehtml passes through when a command is set.
+    MenuItem item1 = 
+      bar.addItem(SafeHtmlUtils.fromSafeConstant(html), BLANK_COMMAND);
+    assertEquals(html, item1.getHTML().toLowerCase());
+    assertEquals(BLANK_COMMAND, item1.getCommand());
+    assertEquals(bar, item1.getParentMenu());
+    
+    // ensure safehtml passes through when a submenu/popup is set.
+    MenuBar foo = new MenuBar(true);
+    MenuItem item2 = foo.addItem(SafeHtmlUtils.fromSafeConstant(html), bar);
+    assertEquals(html, item2.getHTML().toLowerCase());
+    assertEquals(bar, item2.getSubMenu());
+    assertEquals(foo, item2.getParentMenu());
+  }
+
   /**
    * Test that the selected item points to the correct item.
    */
diff --git a/user/test/com/google/gwt/user/client/ui/MenuItemTest.java b/user/test/com/google/gwt/user/client/ui/MenuItemTest.java
index 17d0342..5be7e4c 100644
--- a/user/test/com/google/gwt/user/client/ui/MenuItemTest.java
+++ b/user/test/com/google/gwt/user/client/ui/MenuItemTest.java
@@ -16,6 +16,7 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Command;
 
 /**
@@ -23,11 +24,24 @@
  */
 public class MenuItemTest extends GWTTestCase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.UserTest";
   }
 
+  public void testSafeHtmlWithCommand() {
+    Command command = new Command() {
+      public void execute() {
+      }
+    };
+    MenuItem item = new MenuItem(SafeHtmlUtils.fromSafeConstant(html), command);
+    
+    assertEquals(html, item.getHTML().toLowerCase());
+    assertEquals(command, item.getCommand());
+  }
+
   public void testSetCommandWithMenuBar() {
     Command command = new Command() {
       public void execute() {
@@ -44,6 +58,14 @@
     assertEquals(command, item.getCommand());
   }
 
+  public void testSafeHtmlWithSubMenu() {
+    MenuBar subMenu = new MenuBar();
+    MenuItem item = new MenuItem(SafeHtmlUtils.fromSafeConstant(html), subMenu);
+    
+    assertEquals(html, item.getHTML().toLowerCase());
+    assertEquals(subMenu, item.getSubMenu());
+  }
+
   public void testSetCommandWithoutMenuBar() {
     Command command = new Command() {
       public void execute() {
@@ -59,6 +81,18 @@
     assertEquals(command, item.getCommand());
   }
 
+  public void testSetSafeHtml() {
+    Command command = new Command() {
+      public void execute() {
+      }
+    };
+    MenuItem item = new MenuItem("foo", command);
+    item.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, item.getHTML().toLowerCase());
+    assertEquals(command, item.getCommand());
+  }
+
   public void testSetSubMenuWithMenuBar() {
     MenuBar bar = new MenuBar();
     MenuBar submenu = new MenuBar();
diff --git a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
index 92c6054..d1e288a 100644
--- a/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RadioButtonTest.java
@@ -23,6 +23,7 @@
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 
 /**
@@ -38,6 +39,9 @@
     }
   }
 
+  private static final String html1 = "<b>hello</b><i>world</i>:)";
+  private static final String html2 = "<b>goodbye</b><i>world</i>:(";
+
   /**
    * TODO: Re-enable when we figure out how to make them work properly on IE
    * (which has the unfortunate property of not passing synthesized events on to
@@ -216,6 +220,18 @@
     assertEquals("label", secondChild.getTagName().toLowerCase());
   }
 
+  public void testSafeHtml() {
+    RadioButton radio = 
+      new RadioButton("radio", SafeHtmlUtils.fromSafeConstant(html1));
+    
+    assertEquals("radio", radio.getName());
+    assertEquals(html1, radio.getHTML().toLowerCase());
+    
+    radio.setHTML(SafeHtmlUtils.fromSafeConstant(html2));
+    
+    assertEquals(html2, radio.getHTML().toLowerCase());
+  }
+
   private void doClick(Element elm) {
     NativeEvent e = Document.get().createMouseDownEvent(0, 25, 25, 25, 25,
         false, false, false, false, NativeEvent.BUTTON_LEFT);
diff --git a/user/test/com/google/gwt/user/client/ui/ResetButtonTest.java b/user/test/com/google/gwt/user/client/ui/ResetButtonTest.java
new file mode 100644
index 0000000..524ce9c
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/ResetButtonTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 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.user.client.ui;
+
+import com.google.gwt.dom.client.EventTarget;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+
+/**
+ * Tests for {@link ResetButton}.
+ */
+public class ResetButtonTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  private static class H implements ClickHandler {
+    boolean clicked;
+    EventTarget target;
+
+    public void onClick(ClickEvent event) {
+      target = event.getNativeEvent().getEventTarget();
+      clicked = true;
+    }
+  }
+
+  private static final String html = "<b>hello</b><i>world</i>";
+
+  public void testSetSafeHtmlConstructor() {
+    ResetButton button = new ResetButton(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+
+  public void testSafeHtmlWithHandler() {
+    H handler = new H();
+    ResetButton button = 
+      new ResetButton(SafeHtmlUtils.fromSafeConstant(html), handler);
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
index 086ed09..803d95d 100644
--- a/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
+++ b/user/test/com/google/gwt/user/client/ui/RichTextAreaTest.java
@@ -27,6 +27,7 @@
 import com.google.gwt.junit.DoNotRunWith;
 import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Timer;
@@ -40,7 +41,8 @@
  */
 public class RichTextAreaTest extends GWTTestCase {
   static final int RICH_TEXT_ASYNC_DELAY = 3000;
-  
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
@@ -326,6 +328,49 @@
   }
 
   /**
+   * Test that a delayed set of safe html is reflected. Some platforms have
+   * timing subtleties that need to be tested.
+   */
+  @DoNotRunWith(Platform.HtmlUnitUnknown)
+  public void testSetSafeHtmlAfterInit() {
+    final RichTextArea richTextArea = new RichTextArea();
+    delayTestFinish(RICH_TEXT_ASYNC_DELAY);
+    richTextArea.addInitializeHandler(new InitializeHandler() {
+      public void onInitialize(InitializeEvent event) {
+        richTextArea.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+        assertEquals(html, richTextArea.getHTML().toLowerCase());
+        finishTest();
+      }
+    });
+    RootPanel.get().add(richTextArea);
+  }
+
+  /**
+   * Test that an immediate set of safe html is reflected immediately and after
+   * the area loads. Some platforms have timing subtleties that need to be
+   * tested.
+   */
+  @DoNotRunWith(Platform.HtmlUnitUnknown)
+  public void testSetSafeHtmlBeforeInit() {
+    final RichTextArea richTextArea = new RichTextArea();
+    delayTestFinish(RICH_TEXT_ASYNC_DELAY);
+    richTextArea.addInitializeHandler(new InitializeHandler() {
+      public void onInitialize(InitializeEvent event) {
+        new Timer() {
+          @Override
+          public void run() {
+            assertEquals(html, richTextArea.getHTML().toLowerCase());
+            finishTest();
+          }
+        }.schedule(100);
+      }
+    });
+    richTextArea.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    RootPanel.get().add(richTextArea);
+    assertEquals(html, richTextArea.getHTML().toLowerCase());
+  }
+
+  /**
    * Test that delayed set of text is reflected. Some platforms have timing
    * subtleties that need to be tested.
    */
diff --git a/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java b/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
index 1295213..3cb288b 100644
--- a/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/StackLayoutPanelTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.event.logical.shared.BeforeSelectionHandler;
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -29,13 +30,14 @@
  * Tests for {@link StackLayoutPanel}.
  */
 public class StackLayoutPanelTest extends WidgetTestBase {
-
   static class Adder implements HasWidgetsTester.WidgetAdder {
     public void addChild(HasWidgets container, Widget child) {
       ((StackLayoutPanel) container).add(child, new Label("Header"), 1);
     }
   }
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   private class TestSelectionHandler implements
       BeforeSelectionHandler<Integer>, SelectionHandler<Integer> {
     private boolean onBeforeSelectionFired;
@@ -60,6 +62,15 @@
     }
   }
 
+  public void testAddWithSafeHtml() {
+    StackLayoutPanel panel = new StackLayoutPanel(Unit.EM);
+    panel.add(new HTML("foo"), SafeHtmlUtils.fromSafeConstant(html), 1.0);
+    
+    assertEquals(1, panel.getWidgetCount());
+    assertEquals(html, 
+        panel.getHeaderWidget(0).getElement().getInnerHTML().toLowerCase());
+  }
+
   public void testAttachDetachOrder() {
     HasWidgetsTester.testAll(new StackLayoutPanel(Unit.EM), new Adder(), true);
   }
@@ -109,6 +120,15 @@
     assertEquals(1, p.getWidgetIndex(l));
   }
 
+  public void testInsertSafeHtml() {
+    StackLayoutPanel panel = new StackLayoutPanel(Unit.EM);
+    panel.insert(new HTML("foo"), SafeHtmlUtils.fromSafeConstant(html), 1.0, 0);
+    
+    assertEquals(1, panel.getWidgetCount());
+    assertEquals(html, 
+        panel.getHeaderWidget(0).getElement().getInnerHTML().toLowerCase());
+  }
+
   public void testInsertWithHTML() {
     StackLayoutPanel p = new StackLayoutPanel(Unit.EM);
     Label l = new Label();
@@ -201,6 +221,16 @@
     handler.assertOnSelectionFired(false);
   }
 
+  public void testSetHeaderSafeHtml() {
+    StackLayoutPanel panel = new StackLayoutPanel(Unit.PX);
+    RootPanel.get().add(panel);
+    panel.add(new HTML("bar"), "foo", 1.0);
+    panel.setHeaderHTML(0, SafeHtmlUtils.fromSafeConstant(html));
+    Widget header = panel.getHeaderWidget(0);
+    
+    assertEquals(html, header.getElement().getInnerHTML().toLowerCase());
+  }
+
   /**
    * For legacy reasons, {@link StackLayoutPanel#showWidget(Widget)} should call
    * {@link StackLayoutPanel#showWidget(int)}.
diff --git a/user/test/com/google/gwt/user/client/ui/SubmitButtonTest.java b/user/test/com/google/gwt/user/client/ui/SubmitButtonTest.java
new file mode 100644
index 0000000..9132c7c
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/SubmitButtonTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 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.user.client.ui;
+
+import com.google.gwt.dom.client.EventTarget;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
+
+/**
+ * Tests for {@link SubmitButton}.
+ */
+public class SubmitButtonTest extends GWTTestCase {
+
+  private static final String html = "<b>hello</b><i>world</i>";
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  private static class H implements ClickHandler {
+    boolean clicked;
+    EventTarget target;
+
+    public void onClick(ClickEvent event) {
+      target = event.getNativeEvent().getEventTarget();
+      clicked = true;
+    }
+  }
+
+  public void testSetSafeHtmlConstructor() {
+    SubmitButton button = 
+      new SubmitButton(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+
+  public void testSafeHtmlWithHandler() {
+    H handler = new H();
+    SubmitButton button = 
+      new SubmitButton(SafeHtmlUtils.fromSafeConstant(html), handler);
+    
+    assertEquals(html, button.getHTML().toLowerCase());
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/TabBarTest.java b/user/test/com/google/gwt/user/client/ui/TabBarTest.java
index 4b88b70..a91e8bb 100644
--- a/user/test/com/google/gwt/user/client/ui/TabBarTest.java
+++ b/user/test/com/google/gwt/user/client/ui/TabBarTest.java
@@ -20,6 +20,7 @@
 import com.google.gwt.event.logical.shared.SelectionEvent;
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 
@@ -52,6 +53,8 @@
     }
   }
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   int selected;
   int beforeSelection;
 
@@ -60,6 +63,13 @@
     return "com.google.gwt.user.DebugTest";
   }
 
+  public void testAddTab() {
+    TabBar bar = createTabBar();
+    bar.addTab(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, bar.getTabHTML(0).toLowerCase());
+  }
+
   public void testDebugId() {
     // Create a tab bar with a few tabs
     TabBar bar = createTabBar();
@@ -96,6 +106,13 @@
     assertTrue(bar.isTabEnabled(1));
   }
 
+  public void testInsertTab() {
+    TabBar bar = createTabBar();
+    bar.insertTab(SafeHtmlUtils.fromSafeConstant(html), 0);
+    
+    assertEquals(html, bar.getTabHTML(0).toLowerCase());
+  }
+
   public void testSelect() {
     // Create a tab bar with three items.
     final TabBar bar = createTabBar();
@@ -170,6 +187,14 @@
     handler.assertOnSelectionFired(false);
   }
 
+  public void testSetTabSafeHtml() {
+    TabBar bar = createTabBar();
+    bar.insertTab("foo", 0);
+    bar.setTabHTML(0, SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, bar.getTabHTML(0).toLowerCase());
+  }
+
   public void testGetHTML() {
     final TabBar bar = createTabBar();
     bar.addTab("foo");
diff --git a/user/test/com/google/gwt/user/client/ui/TreeItemTest.java b/user/test/com/google/gwt/user/client/ui/TreeItemTest.java
index dcd0d0e..df4ebf3 100644
--- a/user/test/com/google/gwt/user/client/ui/TreeItemTest.java
+++ b/user/test/com/google/gwt/user/client/ui/TreeItemTest.java
@@ -16,12 +16,15 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 
 /**
  * Tests the {@link TreeItem}.
  */
 public class TreeItemTest extends GWTTestCase {
 
+  private static final String html = "<b>hello</b><i>world</i>";
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.user.User";
@@ -121,6 +124,18 @@
     }
   }
 
+  public void testSafeHtmlConstructor() {
+    TreeItem item = new TreeItem(SafeHtmlUtils.fromSafeConstant(html));
+    
+    assertEquals(html, item.getHTML().toLowerCase());
+  }
+
+  public void testSetSafeHtml() {
+    TreeItem item = new TreeItem("foo");
+    item.setHTML(SafeHtmlUtils.fromSafeConstant(html));
+    assertEquals(html, item.getHTML().toLowerCase());
+  }
+
   /**
    * Test that setting the widget to null does not modify the widget. See issue
    * 2297 for more details.